EASY BASE USERS MANUAL Contents System Overview.............................. 1 Data Management Principles................... 2 Form Design.................................. 6 Relationships and Lookups.................... 11 Data Entry................................... 15 Procedures (Reporting)....................... 20 Procedures (Transactional)................... 36 User Menus................................... 39 External File Access......................... 43 Data File Format............................. 45 System Requirements and Limitations.......... 46 DOS Filename Convention...................... 47 Selected Programming Topics.................. 49 Easy Base is copyright (c) John Turnbull 1994 published by:- Easy Software Tel/FAX (044) (0) 1625 614669 3 Brookside Court CIS 100410,717 Prestbury Road Macclesfield SK10 3BR UK ................................................................................ TERMINOLOGY Field The storage space for an individual data item. Record A set of related data items. Form The storage space for a set of records. Procedure A set of instructions which manipulate the data stored in forms. Relationship A record in the relationships form recording a link between forms. ................................................................................ EASY BASE SYSTEM OVERVIEW Easy Base is a complete rapid programming system for data management. Virtually every data management problem can be broken down into three areas. Creating disk files (referred to as "Forms" in Easy Base) in which to store data, creating procedures which manipulate that data and presenting those forms and procedures in a logical menu system for use. In Easy Base you create the forms in which to store data in a simple screen-painting environment which not only designs the data file but at the same time provides a default data entry screen for your data. As you place the "Fields" in which data is to be stored you can use relational links ("Lookups") to import data from other forms. Each field you create for data storage is also treated as a deriveable "Cell" similar to a spread sheet. You can make almost any calculation or derivation within a field as, apart from all arithmetic, relational and logical operators, Easy Base also provides a set of over fifty functions covering everything from Modulo arithmetic to spelling out dates. Once you have created your forms you can use the default screen to enter and view your data using the "Data Entry" system. Once you have data stored you will need to be able to manipulate it and report on it. Easy Base provides a combined transaction and reporting system ("Procedure Generator"). With the procedure generator you can use the default screens you have designed or create custom screens in which to gather input either from the keyboard or from relational Lookups. You then instruct Easy Base what to do with this information using a simple "Basic" like programming language. If your procedure is transactional you have commands to enter, modify or delete records in any number of forms within a single procedure. If your procedure is reporting then there are commands to group, order and list data in almost every conceivable way. You now have all the "Parts" required to create a useful data management program. All that remains is to tie your procedures to a menu system so that other people can use your application without having to know anything about Easy Base. Creating an end user menu system in Easy base is as simple as filling in a form with the text you wish to display and the procedure or form you wish to run. You give at least one of your menus a start up password. If you then restart Easy Base but sign on with that password instead of your developers password then you will be running your own custom designed program. - 1 - ................................................................................ DATA MANAGEMENT PRINCIPLES In Easy Base, creating forms and entering data is very easy. You will be tempted to rush on and create programs for yourself without reading the "Bumf". However, unless you are an experienced data programmer, you should at least read this section and the one on Relationships before embarking on any serious project. The crux of data management is "Data Integrity" or "Data Verification". You might know that "A Smith", "Smith's Garage" and "Smith and Son" are all the same customer of yours but your computer definitely does not! If you have a small business you might wish to use Easy Base to create invoices - you might be tempted to start by creating an invoice form in which you enter your customers name, work done and price. - DON'T - Start instead by creating a form to hold each of your customers' names, addresses, credit limit etc. If you sell things then create a form to hold each of your stock items with their name, partno, price etc. These are your "Core" data forms from which you "Lookup" data for other purposes. Each of your "Core" data forms has a "Unique" field which defines the record as an entity. "Smith's Garage" will always be "Smith's Garage" and the lookup function described later will not allow any other representation to be entered. Although of less significance than "Data Integrity", the names which you give to forms and fields are very important and worth mentioning now. When you come to write "Lookup" derivations and later, Procedural code you have to refer to your data by a combination of its form and field names. Please give considerable thought to the names you use. Each name should be short but fully describe the form or field. The names of forms should be plural and the names of fields singular. For example - a form which is to hold details of your customers should be called "Customers", the name field should be called "Name" and the credit limit field should be called "Creditlimit" . When you need to lookup data from this form the lookup function will be written - Lookup(customers,name) and when you write procedures the data will be referred to as customers.name , customers.creditlimit etc. If you did not follow this naming convention and called the form "F1" , the name field "customer" and the credit limit field "Max cred" then writing procedure code would be extremely frustrating. It is equally important to give the same name to fields which hold the same data in different forms. If you already had a form called "Employees" which had fields "Worksno", "Name", "Address" and "Taxcode" and you then created a "Payslips" form the fields which hold the employee's name and taxcode should also be called "Name" and "Taxcode". This not only makes it easier to remember field names but when you come to write - 2 - ................................................................................ procedure code, data can be transferred between one form and another with the command "Copy all from". This command only transfers data between fields with the same name. If you have given different names to the fields in the two forms you will have to transfer each individual field separately. The fields which you create are of four general types - The definition (unique) field, grouping fields, ordering fields and descriptive fields. When you create your "Core" data forms it will be fairly obvious which is the definition field. In the "Employees" form "Worksno" defines the record. In a "Manufacturers" form "Name" defines the record. As a general rule, each form should have a definition field. There is an exception to this where a form is used to store temopary lists (described later) but for the moment you should expect to have a definition or "Unique" field on each form to prevent duplicate entries. When you create secondary forms which lookup data from your "Core" forms the data which defines the record as an entity will not necessarily be contained solely in one of the fields you wish to display. As an example - A magazine wholesaler has two "Core" forms, one containing details of the magazines he supplies and one containing customers details. He creates a form on which to record orders from his customers. This "orders" form has three fields, "Name"(for the customer), "Magazine" and "Quantity". When a customer phones in an order for a particular magazine the wholesaler will need to be warned if this particular customer has already ordered this particular magazine but no one field defines the record. In fact the record is defined as unique by a combination of the two fields "Name" and "Magazine" In this case, a fourth field should be added to the form in which the two fields "Name" and "Magazine" are combined using the "jointext" function. This field is then the "Unique" field and no duplicate entries will be allowed. In many secondary forms the records definition will be even less obvious but if you are to create data storage for flexible reporting you should always attempt to create a suitable "unique" field. For example :- An "Aircraft" form has a field "Manufacturer" which is looked up from a "Manufacturers" form. It also has fields for "Name" and "Mark". The definition of an aircraft is what it is known as. If it has a name then it is known as a combination of the manufacturer and the name (Supermarine Spitfire) but if it does not have a name it is known as a combination of the manufacturer and mark (English Electric P1b) Even in these more complicated situations you can still create a unique field to prevent duplicates. In the above example you would create the unique field "Knownas" and derive it with the - 3 - ................................................................................ formula - Jiontext(manufacturer,if(name = blank,mark,name)) When you define a field as unique Easy Base automatically indexes this field. The second type of field is a "Grouping" field. This is a field which will be used in procedures to select subsets of records. In the "Aircraft" form you might add a field "Type" which would qualify each record as belonging to a group - "Fighter", "Bomber", "Transport" etc. Grouping fields should also be defined as indexed and should always be subject to data integrity checking. Where the number of groups is small (17 or less) Easy Base provides a quick method of data verification in the "Choice" field type. If the number of groups is larger than 17 then you should create a "Core" form to hold the group names and look them up into the secondary form. The third type of field is used for ordering data. In many instances the order in which you wish to print or view data will be that of the definition field or one of the grouping fields but not always. In the "Aircraft" form you might wish to list them by the dates they were first introduced or by the total production runs. In order to do this you would have to add fields for "Date" and "Production". You would later write procedures to list the aircraft with "Date in order" or "production in order". Ordering fields should also be indexed but they need not necessarily be checked for data integrity. Fields which are not used for ordering or grouping are descriptive and need not be indexed or integrity checked. One of the most common mistakes made by beginners to data management is to create different forms for the same data. With the "Aircraft" form above you might be tempted to save all the military aircraft of World War 1. Later you might create a second form for the aircraft of World War 2. This would be a mistake. The data you are recording is "Aircraft". The era to which they belong should simply be another "Grouping" field. If having saved your data you were asked for a list of all "Boeing" military aircraft showing which wars they were used in then this could be achieved with one simple procedure if they were in one form but would be rather more difficult if they were in two. That example was fairly obvious but on many occasions it will be easy to assume that two or more sets of data are separate when in fact they are simply groups of the same. Should you decide to write your own accounting program (Which is not as daunting a task as it might seem on the surface) You might be tempted to create forms for a Sales Ledger, Nominal Ledger and Customers Accounts. In fact the entries in the - 4 - ................................................................................ Nominal Ledger and Customers Accounts are simply sub groups of the entries in the Sales Ledger. Provided that you include grouping fields for the customers account number and nominal account name you can construct customers and nominal accounts when required by extracting and totalling the sub sets. There is no need to save them as separate data. The final problem you will encounter when deciding how to store data is that of "Related Lists". Consider the "Aircraft" form. If you had a grouping for "Airliner" you might wish to record all the airlines which operate each aircraft. You cannot just add fields to the "Aircraft" form - One airliner might only be operated by one airline and another might be operated by fifty. To store this data you need another form let's call it Userlist with fields "Aircraft" , "Airline" and "Uni" which is the unique field derived by joining the other two. The "Aircraft" field is looked up from the "Aircraft" forms unique field "Knownas" and the "Airline" field is looked up from the "Airlines" form "Name" field which is also unique. In this form you enter one record for each combination of aircraft and airline. When you come to report on your data you can list single records from the main "Aircraft" form together with all related records from the "Userlist" form. ...................PROCEDURE CODE............. declare output fields aircraft.knownas : Aircraft.production :aircraft.seats userlist.airline end for aircraft with knownas = input.knownas print formfields for userlist with aircraft = aircraft.knownas print userfields next next ...................FORMAT..................... .formfields { Aircraft.knownas field } Production { Prodn. field} Seats {Seats field } Operated by :- .userfields { Userlist.Airline field } .end - 5 - ................................................................................ FORM DESIGN To start designing your forms select "Form Design" then "Design new Form" from the menu system. You are presented with a blank form. Each form has four pages. To move from one page to the next use the PgDn and PgUp keys. To move the cursor around on a page use the arrow keys. Designing your form is a bit like designing a form on paper. If you were to type on a paper form- Name ................. Address ................. ................. ................. ................. Then in Easy Base you type Name and Address as above but instead of typing the dots you define fields for the data to be entered to. Easy Base provides several facilities for "Polishing" the presentation of your forms and these are covered first before moving on to field definition. If you wish to enclose your text within boxes or in some tabular format Press F3 and select "Line Drawing". To draw lines on the screen hold down the Alt key, The Ctrl key or both and drive the cursor around with the arrow keys. The Alt key draws double thin lines, the Ctrl key draws single thin lines and a combination of both draws a thick single line. Press Esc when you are finished line drawing to return to normal editing. If you wish to shade areas of the screen then again press F3 and select "Shading". Shading works much the same as Line Drawing. If you require Greek, Mathematical or International characters which cannot be typed directly from the keyboard then press F3 and select either "Greek and Mathematical" or "International" A menu of all such characters provided by your PC will appear. The one you select is printed to your form at the cursor position. If you wish to use other than the default text colour then press F4 after you have typed your text. In each Easy Base screen colour set you can select one of two alternate text colours or "Blink" - choose 1, 2 or 3 . To change the colour of your text or lines just hold down the shift key and drive the cursor over the text you want to change with the arrow keys. Press Esc when you have finished colouring your form. Text input in the form designer has "overtype" as the default. If you wish to move text (or fields) to the right press the - 6 - ................................................................................ Ins key. Insert mode is indicated by a block cursor and Overtype by an underscore cursor. (This is the opposite to all other editors in Easy Base as it keeps the underscore cursor as the default) To insert a blank line above text or fields press F1. You cannot scroll text or fields between pages in form design. If you need to move areas of your form then press F9, shade the rectangle you wish to move and move it around with the arrow keys. You can also transport the rectangle between pages with the PgUp and PgDn keys. F9 can also be used to erase areas of the screen. When you are ready to define the data fields, position the cursor where you want the field to start and press F10. A window opens into which you enter all the attributes for the field. The first attribute is "Field Name". If you have typed text to the left of the field then Easy Base will have inserted this as a default in the Field Name attribute. If it's not the name you want just edit it. When you are happy with the field name press return or the down arrow to the "Data Type" attribute. A menu appears with the nine different field types. (The field types are described fully in the Programmers Reference) When you have chosen a field type the cursor automatically moves down to the "Field Length" attribute if you have chosen "Text", "Integer", "Fixed Point" or "Floating Point" and to the "Mandatory Entry" attribute if you have chosen one of the others. Enter the field length you require in characters. If you have chosen "Fixed Point" as the field type there are two entries, one for the digits left of the decimal point and one for the digits right of it. If your field is to hold a currency value then the second entry will of course be 2. You must supply values for the first three field attributes. The others all have preset defaults so you can save your field at this point if none of the others have to be changed. The next Field Attribute is "Mandatory Entry" which has a default of "No". You can set this to "Yes", "No" or "If". If you set it to "Yes" then Easy Base will not allow a record to be filed with this field left blank. If you set it to "If" then the "Code Snippet" editor opens up and you can enter the condition under which an entry becomes mandatory. If you were designing a "Payments" form and one of the fields "Paymethod" could be filled with either "Cash" or "Cheque". Then the field "ChequeNo" would have to be filled only if the "Paymethod" field had "Cheque" entered in it. To make an entry mandatory - 7 - ................................................................................ in the "Chequeno" field only if "Paymethod" is "Cheque" enter - paymethod = "cheque" in the Code Snippet editor. When you use the Code Snippet editor for Mandatory Entry and for User Entry, only the condition is entered :- total < 100 name = blank length = blank or breadth = blank the "if" is assumed. If you set the "Mandatory Entry" attribute to either "Yes" or "If", a window will open into which you can type the message which you wish to be displayed should an attempt be made to file a blank entry. If you leave the message blank Easy Base will supply the default message "This field must be filled !". The next attribute is "Unique". This can be set to "Yes" or "no". You can only have one unique field on a form. If you have already defined a field as the unique field and you change your mind and define another then Easy Base will automatically cancel the unique attribute on the first field. Indexing is automatically set to "Yes" for the unique field. The next attribute is "Indexed". Select "Yes" or "No" When you set "Index" to "yes", Easy Base Creates a separate "Index" file in which the contents of the field are kept in up to date order. Index files are used by Easy Base in exactly the same way that you would use an index in a book to find things quickly. The next attribute is "User entry". This has a default of "Yes" but can be set to "No" or "If". If you set this attribute to "No" then the cursor will not visit the field during record entry so the user cannot alter its contents. You would normally set this to "No" if the contents are derived or calculated from the values of other fields. You can set this attribute to "If" if the value entered in another field makes this one superfluous. For example, in the "Aircraft" form, if you had a field "Passengers" and the type had been entered as "Fighter" there would be no point in the cursor moving to the "Passengers" field. When the Code Snippet editor opens you could type:- type = "Transport" or type = "Airliner" The next field attribute is "Display". When the cursor reaches this attribute a menu appears with the seven different ways in which the field can be displayed. - 8 - ................................................................................ The field display attribute settings have the following meaning. 1. FIELD The field's size is displayed as a block which shows up against the screen background. 2. TEXT The field size does not show up against the screen background and the contents are in the default text colour. 3. 1ST ALT COL. As Text but with the contents in the first alternate colour 4. 2ND ALT COL As Text but with contents in the second alternate colour. 5. BLINKING As Text but the contents blink. 6. INVISIBLE Neither the size nor the contents can be seen. Invisible fields are used to hold compound index fields and the results of intermediate calculations which the user need not see. 7. CODEWORD FIELD The size of a codeword field shows against the screen background but its contents are masked by stars. Codeword fields are used to collect passwords for restricted menus or procedures. An onlooker cannot see the password which is being entered. The final field attribute is "Derived". If you set this to "yes" then the Code Snippet editor opens and you can enter the formula by which the fields contents are to be derived. In the Code Snippet editor you can enter almost any derivation formula. Formulae consist of field names operators and functions. price * markup VATon(net,vatrate) datetext(system date) if(sex = male,"Mr","Ms") - 9 - ................................................................................ All the operators and functions are fully described with examples of how they are used in the Programmers Reference. If in the Code Snippet editor you cannot remember a field or function name then Press F1 for the reminder lists. There is a cut and paste facility in the Code Snippet editor. To mark text hold down the shift key and move the cursor with the arrow keys. When you release the keys the "Cut" or "Copy" choice will appear. To paste text, position the cursor at the insertion point and press Shift + Ins. Text which is cut or copied from the derivation of one field can be pasted into the derivation of any other field in any other form. When you have finished entering the field attributes press F2 to save the field. When you have defined all the fields press F2 to save the form. There is one other facility in the Form Design editor. If you press F5 at any time you enter "Derivation Test Mode". In derivation test mode you can enter data to your fields and check if your derivations work correctly. Any fields which you have defined as invisible are not hidden in test mode. The main advantage of test mode as opposed to testing in Record Entry comes not when you are designing new forms but when you wish to modify one after you have saved many records in it. If you add, delete or alter the length of a field then the entire data file has to be reformatted and this takes time. With "Derivation Test Mode" you can ensure that the modifications you have made are correct before reformatting. The only exception to test mode is if you have added a new lookup function and you have not yet entered the relationship. If you select test mode with a relationship missing you will get an error message and be returned to Form Design. When you save your form Easy Base tests it in derivation test mode before saving. If it cannot find a relationship you will be given an error message and offered the choice to remain in Form Design (which you would do should you know that the relationship exists and you must therefore have mistyped a lookup formula) or to save and go to the relationships form Which you would do if the relationship had not yet been entered) If you opt to go to Relationships Easy Base will transfer you to the relationships form and back again via a macro. - 10 - ................................................................................ RELATIONSHIPS AND THE LOOKUP FUNCTION In Easy Base the Lookup Function together with pre-recorded relationship links provide two of the most important facilities of a data management system. 1. Reuse of previously entered data. 2. Verification of text data. Consider the situation where you have designed a form to hold information about your business's customers. The form has an "accountno" field which has been derived as "Sequence" and this is therefore the "Unique" field on the form. It also has fields "Name" and "Address". All your customers have now been recorded in this form. You now want to create an invoice form. Each invoice issued will have to have a customer's name and address entered on it. All the names and addresses are already filed in Easy Base so they do not have to by typed again. Provided that Easy Base knows which customer's name and address is required it can copy it automatically from the "Customers" form to the "Invoice" form. The way in which Easy Base accomplishes this is exactly the same as you would accomplish the task manually in a hand written system. If you knew where to find the book in which your customers names had been written and you knew the customers account number then you could find the customers name and address. The only slight difference for the computer is that while you would consider it "Obvious" that the account number on the invoice would be the same as the account number in the addresses book your computer does not - You have to tell it. To tell Easy Base where to look and that the "accountno" is the link, you enter a record in the "Relationships" form. When you select "Relationships" from the main menu you will see five fields to be filled. The first field is the name of the form which data is to be copied to. In this case you will enter "Invoices". You will notice that easy base has displayed a list of all your form names and that you must choose one. You cannot enter the name freehand. This "internal" data verification is the same as you will be doing for your own data later. The second field is for the name of the form in which the data can be found. In this case select "Customers". The next two fields record which fields in the primary and secondary form hold the "Linking" data. In this case select "acountno" in both. - 11 - ................................................................................ The final field is the name of the relationship record. You will notice that Easy Base has already entered a default name of "Customers". The relationship name can be anything you like but as the "Lookup" function which you are about to use quotes the relationship name as its first parameter and the field to be copied as its second then Lookup(customers,name) has to be more meaningful and easy to remember than any other name you could give. When you have entered all the fields press F2 to save the relationship, return to Form Design and load your "Invoice" form. All that remains to do now is edit the field attributes of the "Name" and "address" fields. To edit a field you can either press F10 with the cursor on the form background and select the field to edit by name, or you can position the cursor within the field you wish to edit and then press F10, in which case the field attribute window will open automatically. Position the cursor in the "Name" field and press F10. Move the cursor to the "Derivation" attribute and set it to yes. (you can move the cursor from the "Name" attribute directly to the "Derived attribute by pressing the up arrow) When the Code Snippet window opens type - Lookup(customers,name) and press F2. If you had not already done so then set the "User Entry" attribute to "No". Press F2 to save the new field attributes and then do the same for the "Address" field, this time entering the derivation - Lookup(customers,address) To test that you have typed the lookups correctly press F5 for Derivation Test Mode. Enter a customers account number in the "Acountno" field and press the return key. If your formulae are correct the customers name and address will appear in the "Name" and "Address" fields. In this example you have performed two "Secondary" lookups. Both the "Name" and "Address" fields were found using the "accountno" link which you had to enter correctly in order to find the other two fields. The real power of the Lookup function is only realized when you perform "Primary" and "Secondary" lookups. In a "Primary" lookup the field whose value is to be looked up is also the "Link". It is "Primary" lookups which are used for data integrity checking. - 12 - ................................................................................ Consider the "Aircraft" and "Manufacturers" forms which were discussed earlier. Suppose that you want to lookup the manufactures name and the name of his base airfield into the "Aircraft" form. The definition field in the "Manufacturers" form is "Name" - There is no handy "accountno". You are going to have to enter a relationship between "Aircraft" and "Manufacturers" linking the two fields "Manufacturer" in the "Aircraft" form with "Name" in the "Manufacturers" form. Having done this you could derive the "Base" field in the "Aircraft" form with - Lookup(manufacturers,base) - and it would be looked up when you entered the manufacturers Name just as in the invoice example. But what of the "Manufacturers" field itself. Was the name you entered in the manufacturers form "A.V.Roe", "A.V.Roe & Co." or "AVRO A/C Co.". Easy Base provides a simple solution to this problem. Having entered the relationship, return to Form design and enter the lookup derivations. Derive the "Base" field with - Lookup(manufacturers,base) and the "Manufacturers" field with Lookup(manufacturers,name) This time, leave the "User Entry" attribute set to "Yes" in the "Manufacturers" field. Press F5 for "Test mode". When the cursor enters the "Manufacturers" field type - AV* - and press return. Provided there is only one manufacturer whose name begins with "AV" the Avro name will be looked up into the "Manufacturers" field and its representation will always be exactly the same as the original entry in the "Manufacturers" form. If there are several manufacturers whose names begin with "AV" then a menu will appear listing all of them and you can choose the one you want. As soon as you select the name the secondary lookup "Base" will fill automatically. If you cannot remember the first letters of the name you want to look up - say for example that you could only remember that "Roe" was in the name - then type Roe* and press return. If any manufacturers names begin with "Roe" they will be displayed first. If not Easy Base will fill the "Manufacturer" field with the first name it finds with the letters roe in it. If this is not the one you want press F3. Each time you press F3 Easy Base will find the next name containing the letters until you find the one you want. As a final resort - if you really can't remember what you are looking for - just enter an "*" on - 13 - ................................................................................ its own and press return. Easy Base will then list all the manufacturers names for you to choose from. There is no limit to the number of secondary lookups which can be made from each primary and there is no limit to the number of different forms you can look data up from. If you have many different forms which all look up data from the "Customers" form then they can all use the same relationship name "Customers" but if you have more than one relationship between the same two forms then they must have different names. If you had a "Stock" form with the unique field "Item" and another field "Price" then you could add four fields to your "Invoice" form - "Item", "Quantity" "Price" and "Total". You would enter a relationship "Stock" between "Invoice" and "Stock" with the related fields being "Item" in both forms. In your invoice form you would derive :- Item as Lookup(stock,item) Price as Lookup(stock,price) Total as quantity * price When you entered the "Item" field (primary lookup) the price field would fill automatically and when you entered the "Quantity" the "Total" field would be calculated. However, if you now add four more fields "Item2", "Price2", "Quantity2" and "Total2" you will need another relationship between "Invoice" and "Stock" this time linking "Item2" in the "Invoice file" with "Item" in the stock file and you cannot now use the default name "Stock" for the relationship. Although you can give your additional relationship any name you like, the best name will be "Stock2". Please note that this example is used purely to show the use of multiple relationships between the same two forms. If you are intending to write an invoicing system then unless you know that there will only be a limited number of items on each invoice this is not a practical way to tackle the problem. In a flexible invoicing system each item and quantity is entered via a procedure to a temporary list form whose contents are then printed to the invoice. From V9 the lookup function also accepts a third parameter with which you can specify the display of a field other than that which is being looked up. See "Lookup" in Programmers Reference - 14 - ................................................................................ DATA ENTRY As soon as you have designed forms you can enter and view data directly using the default screen you created. To enter data to a form select "Data Entry" from the main menu and choose the form you wish to use. Your default entry screen will appear with the cursor in the top left field. The top line of the screen shows the name and page number of the form you are using together with the system date and time. Line 2 shows the number of the record you are creating or editing on the left hand side. It is also the line on which any error messages are passed. The bottom line lists the most used function keys and is also the line on which help prompts are displayed. To move the cursor around between fields you can use all of the cursor control keys which work as follows:- The Return key moves from field to field in the order top left to bottom right unless you have overridden this in form design by deriving fields with "Goto (fieldname) Next". The Tab key moves the cursor from field to field in the order bottom right to top left (reverse of Return). The arrow keys move the cursor in the direction indicated. The Home Key moves the cursor to the beginning of the current field if it is not already there and to the first field on the page if it is. The End Key moves the cursor to the end of text if it is in a text field and to the last field on the page if it is not. The PgUp and PgDn Keys move between pages if your form has more than one. When you have entered the data for your first record press F2 to save it to disk. The screen will clear, the message "Record 1 has been added" will appear briefly on line two and you will be ready to enter the next record. If some of your fields are primary lookups then you use them exactly the same as was described for "Derivation Test Mode" by entering part of the text followed by a star and pressing the Return Key. Once you have saved a few records to disk you may wish to view or edit them. You can bring previously entered records back to the screen for editing in several ways. From record creation the F5 Key brings up the first record and subsequent presses - 15 - ................................................................................ bring up the next record. Similarly, from record creation the F4 Key brings up the last record and subsequent presses bring up the previous record. Once you have entered several records this process becomes impracticable and you "search" for the record you wish to view or edit. Position the cursor in any field and type part of the field contents you wish to search for followed by a star and press F3. Searching for records within a form is a similar process to looking up data except that you press the F3 rather than the Return Key to initiate the process. If the field in which you are searching is indexed and more than one record matches the data you have entered then Easy Base will make a list of all the field contents which match for you to choose from. If the field is not indexed then Easy Base will bring up the first record it finds a match in. If this is not the record you want then press F3 again. Easy Base will find another match on each successive press of the F3 key until you find the record you want. As with lookups, Easy Base will search for "Part Matches" after it has exhausted all the records where the entered data matches the beginning of the field and if you enter a star on its own and press F3, Easy Base will list all the field contents for you to choose from. When you have brought a previously entered record back to the screen you will notice that line 2 now displays "Editing Record x of y " rather than "Creating New Record x ". Easy Base automatically changes from "Create" to "Edit" mode when you view a record. The changes which you make on screen are not entered to the record on disk until you press F2. To clear the contents of the field in which the cursor lies rather than delete each character press F6. To return to "Create" mode press F6 twice. Not all of the active function keys are listed on the prompt line. To see a full menu of the function key uses press F1 for the Function Key Menu. The following is a summary of the function key usage in Data Entry:- F1 The F1 Key brings up the function key Menu. F2 The F2 Key writes a new record from "Create" and updates the record on screen from "Edit" mode. - 16 - ................................................................................ F3 The F3 key initiates searches for previously entered records based on the data entered in the current field. F4 The F4 key moves to the previous record when in "Edit" mode and to the last record from "Create" mode. F5 The F5 Key Moves to the next record when in "Edit" mode and to the first record from "Create" mode. F6 The F6 key clears the current field on the first press and returns you to "Create" mode on the second press. F7 The F7 key deletes the record currently on screen in "Edit" mode. When you delete a record with the F7 key it is not actually erased from the disk. It is simply "Flagged" for deletion at the next "Pack" operation. If you delete a record accidentally you can reinstate it any time before the form is next packed. F8 The F8 key creates a new record by copying the record currently on screen. If a new record you wish to create contains similar data to one already entered then you can find the previous entry, change the unique field and copy it with F8 rather than type it all again. F9 If you know the number of the record you wish to view or edit you can press F9 and enter the record number. Easy Base will then bring the record whose number you have entered to the screen. F10 When you press the F10 key Easy Base searches for records which are "Flagged" for deletion. When it finds one it will bring it to the screen. You can reinstate a deleted record by pressing F2 while it is on screen. The F5 key searches for the next deleted record and the Escape key returns you to "Live Records". - 17 - ................................................................................ F11 If you have been viewing records and you wish to return to one which you had on screen earlier then press F11 and Easy Base will back step through the records you have viewed. F12 The F12 key brings up the form's "Options". There are four options in Data Entry. 1. Clear screen on Adding Record. (Default Yes) 2. Confirmation Required to delete Records. (Default Yes) 3. Confirmation Required to abandon Edits (Default No) 4. Clear Field on Editing (Default No) If you change "Clear Screen on adding Record" to "No" then, when you press F2 to file a new record, the data which is written to disk remains on screen ready for the next new record. This is useful if you are entering several records and many of the fields in each record contain the same data. You only have to overwrite the fields which are different each time. If you have many records to delete then set option 2 to "No" and you will be able to delete them without having to confirm each one. If you set option 3 to "Yes" then Easy Base will ask you to confirm that you wish to leave a record which you have edited but not updated to disk. If you set option 4 to "Yes" then Easy Base will clear the old contents of any field you start to edit. This is most useful when used in conjunction with option 1. You can file a record, retain the contents for the next record and when you edit the fields which are different you do not have to first delete the data in them. The options you set for any given form remain with it until changed. They do not revert to the defaults when your computer is turned off and each form can have different option settings. Ctrl + E If you press the "E" key while holding down the Ctrl key you will get the extended "Greek" and "International" characters menu which was discussed in form design. - 18 - ................................................................................ Ctrl + S If you press The "S" key while holding down the Ctrl key you start the Spell-checker. The Spell-checker will check the current field. If it finds a word not included in the Easy base dictionary it will offer you the choices to leave the word and continue, add the word to the dictionary, or choose one of the suggestions for replacement. The Spell checker does not automatically move from field to field but once you have started it, it remains active and will immediately check the next text field you move the cursor to. The Spell-checker is cancelled if you press the Escape key or if you press the F2 key to update the record. - 19 - ................................................................................ PROCEDURES (REPORTING) The Easy Base procedure generator is the means by which you manipulate and report on your data. Each procedure has at least one part, the procedure code. The procedure code contains the instructions you write to tell Easy Base what you want done. If your procedure has an "output", in other words your instructions tell Easy Base to send data to the screen or to the printer, then the procedure must also have an Output Format. The Output Format is where you show Easy Base how you want the data you are about to "output" arranged on the screen or page. If what your procedure is to do depends on variables, ie it requires information from the operator or from Looked up data from one or more of your forms then it also requires an "Input Screen". The Input Screen is where you gather the variable information that your procedure needs in order to carry out its task. Select "procedures" from the main menu and have a look at the items on the procedures menu. You will notice that the menu has pre-selected item 2 "Load Existing Procedure". Other than your first procedure this is the most useful starting point. Item 1, "Create New Procedure" is only required if you wish to start a new procedure after you have another one loaded. The three parts to a procedure mentioned above are created and edited at items 3,4 and 5. Procedures, like forms, are saved to disk and can be re-used repeatedly. Item 6 runs the current procedure and item 7 saves it to disk. Item 8 deletes procedures which are no longer required and Item 9 copies an existing procedure. Often you will require a procedure which is similar to one you have already created. It is much quicker to copy the first procedure and then edit it than to start a new procedure from scratch. Item 10 recalls the last output from a procedure to the screen. If you need to see the output from a procedure but it is not imperative that you have the most up to date information, (close of business / month end figures Etc) then it is much quicker to view the last output than to re-run the procedure. Finally, a small window just below the menu shows the name of the currently loaded procedure. In this case it is "Untitled". - 20 - ................................................................................ If you have not already done so, read the descriptions of the Declare, For..Next, If..Then, Print and Printer Control commands in the Programmers Reference now. These are the basis of all "reporting" procedures and should be thoroughly understood. If you are a programming beginner then some of the examples in the For..Next section may seem a bit advanced - Just ignore them - for the moment it is only important that you understand the principle of the loop and the qualifications that can be applied to it. Now select item 4 to write your first Procedure Code. The next few pages will describe simple reporting procedures based on the "Aircraft" form. To write like procedures for the forms you have designed all you have to do is substitute your form and field names. Before you start, have a look at the function key list on the bottom line. F2 saves your code and checks it. If you press the Escape key your code is still saved but the checking routine is bypassed. If you have written code and find that it is not passed on F2 because, for example, one of your form fields needs to be indexed, then you can still save the code you have written while you modify the form. F3 and F4 provide search and replace facilities similar to a word processor. There is a cut and paste system. To mark code for cutting or copying hold down the Shift key and shade the code with the arrow keys. As soon as you release the keys a menu will pop up with three options - Cut, Copy or Indent. The cut and copy options work exactly the same as in the Code Snippet editor with Shift + Ins used to paste the text. If you select "Indent" then you can indent all the selected lines at once with the left and right arrow keys. If you want to print out your code then press F10. The F1 key, labelled "Help" is the key you use when you can't remember something. It has all the names of your forms, the names of the fields in each form and the names of all Commands, functions, and System values. If Easy Base recognizes the context of your procedure when you press F1 then it will list the names you need (Formnames, fieldnames or Commands). If not a menu will appear from which you can pick which you need. With the cursor at the start of the top line on your blank procedure screen press F1. The "Commands" reminder list appears on the right hand side of the screen. The command you want is the first one , "Declare Output Fields" but before selecting it have a look at how to - 21 - ................................................................................ select from the reminder lists. There are over fifty commands on this list but only the first seventeen are shown. You can scroll though them with the arrow keys but you can also use the inbuilt alphabetic search facility. If you type "o" then the highlight bar will move directly to the "Odd Page Print" command. Take the highlight bar back to the "Declare Output Fields" command either by scrolling or by pressing the Home key and press return. The command will be inserted on the first line, the cursor will move to the second line and the "Forms" reminder list will appear. Select the form which you wish to report on. In my example case this will be "Aircraft". "Aircraft." is inserted on the second line and the "fields" reminder list appears. I select "Knownas". I also wish to list the aircraft's mark and type so I write. Declare output fields Aircraft.knownas : Aircraft.mark : Aircraft.type end Declare the fields you wish to list either by typing them freehand or by pressing F1 for reminders. Now complete your procedure code:- Declare Output fields Aircraft.knownas : Aircraft.mark : Aircraft.type end for Aircraft Print list items next and press F2 to check and save the code. If you have typed everything correctly you will be returned to the Procedures menu. If you have misspelled something then the line with the error will be highlighted and you will get an error message. Correct the error and press F2 again. Easy Base now knows that it is to list the three fields Knownas, Mark and Type from all the records in the "Aircraft" form. It does not know how they are to be arranged or whether they are to be printed or just shown on screen. This information must now be recorded on the procedures "Output Format". Select item 5, "Output Format", from the procedures menu and have a look at the screen. As usual the bottom line shows the function key usage. To insert a blank line you use F1 as in form design. F2 saves the format and the Escape Key abandons it. F3 gives you a line drawing facility similar to that in - 22 - ................................................................................ form design and Ctrl + "E" brings up the Greek and International characters menu. The F10 Key is used to place your output fields. The upper status line shows the paper size you have selected at the left hand edge. If you scroll to the right it also shows where the right hand edge of your paper will be at the three different print sizes 10, 12, and 17 characters per inch. On the right hand side of the screen a small menu will have appeared offering you a choice of Format Section names. You do not have to use one of these they are just to save you time. For the moment select "List Items" from this menu. .List items will appear on the first line and the cursor will move to the second. For a first procedure we will simply list the fields required in columns. To do this move the cursor in along the second line to leave a reasonable margin and press F10 to place the first field. A menu appears listing the three fields which were declared in the procedure's code. I select "Aircraft.knownas". As soon as The field has been selected a window opens showing the default type and length of the field. You can change these defaults if you wish the printed length or type(for numeric fields) to be different in the report to what it is in the form. This window also presents an extra attribute marked "Trim Trailing Spaces" which defaults to "No". If you set this to "Yes" then any blanks at the beginning or end of the fields contents will not be printed at run time. This facility is used mainly for inserting numbers or names into form letter text. Press F2 to accept the defaults. The area which the field will occupy is shown on screen. Now move the cursor to the right and place the other two fields. Finally, press the return key to take the cursor to a new line and type a full stop ".". The section names menu appears again. This time select "End". The format screen now looks like this. .List Items .End Press F2 to save the format. When you do, a new menu will pop up with four choices for the output destination. The exact meanings of these selections will be discussed shortly. For the moment select "Output to Screen". When the Procedures menu appears select item 7 and save your procedure to disk. Now select item 6 and run the procedure. The fields from each record of the "Aircraft" form are listed - 23 - ................................................................................ down the screen. When the list reaches the bottom line the screen starts to scroll. When all records have been listed the screen returns to the start of the list from where you can browse the report. If the list is long you can pause the output by pressing the return key while it is still running. Once the report is complete you can browse through it using the PgUp, PgDn and arrow keys. You can also use the text search facility at F3. When you have finished reading the report press Escape to return to the procedures menu. You can browse the report again at any time by selecting item 10 (Recall Last Output). Try it now. While browsing a report you can also print it out by pressing F10. If you press F10 to print a report from browse mode you invoke a low level print driver which prints the report at 10 CPI, 6 LPI in draft mode. Other font sizes and effects such as Bold and Underline are only available when you direct the report output to the printer at run time. To try printer effects select "Edit Procedure Code" and change The code to:- Declare output fields Aircraft.knownas : Aircraft.mark : Aircraft.type end Bold on 12 CPI for aircraft print list items next Save the new code and select "Edit Output Format". There is nothing to change in the format itself but when you press F2 to save it, this time choose "Choose at Run time" for the output destination. When you now select "Run Procedure", the computer will beep and you will be asked whether the output is to be to the screen or printer. Choose printer and easy base will print your report in bold at 12 characters to the inch. (Assuming you have installed the correct printer driver from the utilities menu) You will notice that while Easy Base was printing your report it also output it to the screen but on completion it returned you to the procedures menu without invoking Browse mode. The output destinations which you choose when saving the output format are not "Either or" choices. Irrelevant of your choice the output is always sent to both the screen and the disk file. It is the disk file that you browse when you select "Recall Last Output". The differences between the choices are that only an output to the screen invokes Browse mode on completion - 24 - ................................................................................ and only an output to printer prints the report. Output to disk is only selected if you want to update reports from a Batch Execute menu. Now let's try something a bit more interesting. So far the report simply lists the aircraft in the order in which the records were filed. To list them in alphabetic order, edit the procedure code and change the "For" line to:- for aircraft with knownas in order Save the code. Easy Base can only list in order if the field you wish the order to be done by is indexed. If the field you have chosen is not indexed you will get an error message. If this happens, save the code by pressing the Escape Key - Save the procedure at item 7 then return to form design. Load your form - edit the attributes for the field changing Indexed to "Yes". You can now reload your procedure and run it. This time the aircraft names will be in alphabetic order. Because a procedure has up to three parts it may not at this stage be obvious how Easy Base is handling the "Saving" or "Abandoning" of separate parts. Here is a quick explanation. If you escape from either the output format or later the input screen and choose to "abandon" it you are abandoning it in the version of the report you are editing only. If you escape from the procedures menu and choose to "abandon" the procedure then, if it is a new "Untitled" procedure it is lost but if it is a procedure which you have loaded for editing then it is only the edits which are abandoned - The original procedure remains unchanged on disk. A procedure which you have loaded for editing is only changed on disk when you save it with item seven from the procedures menu. At any time during the editing of a procedure you can throw away all your edits and return to the original version by reloading it from disk and replying "No" when you are asked if you wish to save the currently loaded version. Suppose now that we wished to list the aircraft in groups by type - all the bombers together - all the fighters together Etc. To do this, edit the procedure code again and change the "For" line to: - for aircraft with type in order This time, when the report is run, all the airliners come first followed by the bombers etc. but the group field "Airliner" , "Bomber" etc. is listed on each line and it would be much - 25 - ................................................................................ neater if it could be separated or printed in Bold or underline. Edit the code again, this time to:- Declare output fields Aircraft.knownas : Aircraft.mark : Aircraft.type end declare variables lasttype as text end for Aircraft with type in order if aircraft.type <> lasttype then print group header lasttype = aircraft.type print list items next In this code we have introduced a text variable "lasttype". During the "For" loop the list items will be printed on each iteration but the group header will only be printed when the type changes Now edit the output format to:- .group header .list items .end The group header starts with a blank line which will separate the groups. It contains only the "Type" field. The list items section contains the "Knownas" and mark fields. When you run this report the output will be:- Airliners Boeing 707 Dehaviland Comet Mk4 Boeing Jumbo Jet 747 Bombers Boeing B52 Avro Vulcan Avro lancaster 2 If you want the group header to be in bold or underline then all you have to do is insert the on and off commands before and after the "Print group header" command using the block If then construction. - 26 - ................................................................................ Declare output fields Aircraft.knownas : Aircraft.type : Aircraft.mark end declare variables lasttype as text end for Aircraft with type in order if aircraft.type <> lasttype then bold on : underline on print group header bold off : underline off end if print list items next As a beginner, you are probably wondering about the reason for the indentations after the "for" and "if" lines. The code will work perfectly well without them. When you come to write more advanced procedures you will have many For loops, Do Loops and If conditions interwoven with each other. If each has its own indentation then you will be able to see at a glance which commands occur within which loops and conditions and your code will be very easy to read and edit. Going back to the "Aircraft" listing procedure, we now have each group separated but the aircraft names themselves are no longer in alphabetic order. This is because we changed index files when we selected "With Type in order". It is now the "Type" groupings which are in alphabetic order. Suppose that we want to keep this grouping but still list the aircraft in each group with their names in order. Neither of the index files on the "Knownas" or "Type" fields can produce this order. We need a combined or "Compound" index on both fields To construct this index, save the present procedure and return to form design. Load the "Aircraft" form and add a new field anywhere on it. Assuming the length of the "Knownas" field as 45 and the length of the "Type" field as 14 the new fields attributes are:- Name Typename Type Text Length 59 Mandatory No Unique No Indexed Yes User Entry No Display Invisible Derived Yes The derivation formula is:- Jointext(spacepad(type,15),knownas) - 27 - ................................................................................ Test that the derivation formula is correct by pressing F5 for test mode. When you type a name into the "Knownas" field and a type in the "Type" field the new field should derive as a combination of the two. Escape from test mode and press F2 to save the form. Easy Base will first re-format the data file to incorporate the new field and then write the new index file. When this is complete, return to the procedure and edit the "For line of the code from:- For aircraft with type in order to For Aircraft with typename in order No change is necessary to the output format. The output will be laid out as before but the names in each group will be in alphabetic order. To "Polish" the "Aircraft" report it would be nice if it had a heading. We would also like to prevent the list from running off the end of the page when printed and add a page number at the foot of each page. To do these things edit the code to:- Declare output fields Aircraft.knownas : Aircraft.type : Aircraft.mark page number 'New Field end Declare variables lasttype as text end bold on print report header for aircraft with typename in order if bottom margin < 1 then bold on : print page footer page feed : print page header : bold off end if if aircraft.type <> lasttype then bold on : underline on print group header bold off : underline off end if print list items next print report footer - 28 - ................................................................................ Now edit the output format to:- .Report header AIRCRAFT LIST BY TYPE .Group Header .List Items .Page header Aircraft List By Type (Cont) .Page Footer - .Report Footer .End The new print sections Report Header, Report Footer, and Page Header contain only fixed text. The new section Page Footer contains the new field "page number" and the "Trim trailing spaces" attribute should be set to "Yes" in this. This will keep the correct spacing of - 9 - and - 10 - when the page numbers are printed. So far all the fields we have printed are from the same form "Aircraft". Suppose that we also wanted to list the country of origin for each aircraft. The "Aircraft" form does not hold this information but the "Manufacturers" form has a field "Nationality". To incorporate this field into the report all we have to do is declare it as an output field and then arrange to have that field in memory when we print the list items. We can load the correct record from the "Manufacturers" form by using the linking data "Name" in the manufacturers form and "Manufacturer" in the "Aircraft" form. This is a similar process to looking up data except that a pre defined relationship is not necessary. We can tell Easy Base exactly what we want within the code. Declare output fields Aircraft.knownas : Aircraft.type : Aircraft.mark Manufacturers.nationality : Page number end Declare variables Lasttype as text end - 29 - ................................................................................ '.....................PRINT REPORT HEADING... print report header '................. for aircraft with typename in order '..................PRINT HEADERS AND FOOTERS... if bottom Margin < 1 then bold on : print page footer page feed : print page header : bold off end if '..................PRINT GROUP HEADERS......... if aircraft.type <> lasttype then bold on : underline on print group header bold off : underline off end if '...............LOAD MANUFACTURERS NATIONALITY.. for manufacturers with name = aircraft.manufacturer Print list items next '.............. next print report footer Because the procedure code is becoming longer, remarks are added to make it easier to see which parts of the code do what. You can add remarks to your code anywhere by prefixing them with an apostrophe. At the point where we are about to print the list items we start another "For" loop. This time "For Manufacturers". When one "For" loop is "Nested" within another, the record currently loaded by the first loop remains in memory while the records selected by the "Nested" loop are processed and all the fields of both records are available at the same time. As we have qualified the "Manufacturers" loop:- for manufacturers with name = aircraft.manufacturer only the single record in which the "Name" field matches the "Aircraft.manufacturer" field which is currently loaded by the outer loop will be selected from the "Manufacturers" form. While we have both the required records in memory we print the list items. All that remains to do now is to edit the output format and add the "Manufacturers.nationality" field to the .List Items section. - 30 - ................................................................................ By nesting loops in this way, you can list data from any number of different forms which have "Linking" data in one of their fields. Where only one record matches as in the example above then the required fields go in the .List items section with the other fields. Where there are many matches (Related list) the fields from the secondary loop have their own print section. (See example on page 5) Now we can print any of the fields from any "Related" forms in any order. We are still, however, listing all the records from the "Aircraft" form and we may for example only wish to print those records which are in the "Bomber" group. Start a new procedure and enter the code:- Declare output fields Aircraft.knownas : Aircraft.type : Aircraft.base end for aircraft with type = "Bomber" print list items next Create the output format placing the three output fields within the .List Items section. When you run this report, only the bombers will be listed but, once more, the aircraft names will be in the order in which they were entered to the form. To get them in alphabetic order we must again use the compound index on the "Typename" field. This time we have to ensure that the loop starts with the first "Bomber" and ends with the last "Bomber". Declare output fields Aircraft.knownas : Aircraft.type : Aircraft.base end declare variables group as text end group = "Bomber" for aircraft with typename > "Bomber" if aircraft.type <> group then exit for print list items next Before starting the "For" loop we set a variable "Group" to the value "Bomber". The "For" loop is then qualified such that the records will be processed with "Typename" in order but starting with the first occurrence of "Bomber" in the field. To stop the loop when all the bombers have been processed we test the contents of the "Aircraft.type" field on each iteration of the - 31 - ................................................................................ loop and when the first record is loaded which is not a bomber we stop processing the loop with the command "Exit For". As in the first procedure, we could now add Page headers, Page footers and number the pages Etc. Suppose however that having created this procedure we now wanted a list of all the "Airliners". We could achieve this by changing "Bomber" to "Airliner" within the code but this would be time consuming. It would be much better if we could tell Easy Base which type group we wanted at the start of the procedure and have Easy Base make the necessary changes. To supply "Variables" to a procedure before running we use an "Input Screen", the third part of a procedure. Save the code and select item 3 (Create Input Screen) from the procedures menu. As soon as you select item 3 Easy Base will ask if you wish to copy an existing form. Type "N" for no. The next screen will be familiar to you. It is exactly the same as the form design screen. When you first designed your forms, the form design routine performed two tasks. It created your form and also a default input screen from which to enter data. Now that you are about to create input screens for procedures, the same routine is used to design the screen. It does not, of course, create a parallel form. All the facilities for "Polishing" your forms - all the facilities for deriving, calculating looking up and testing derivations which you had in Form Design are also available for Input Screen design. The only difference you will notice is that when you define a field, the "Unique" and "Indexed" attributes are marked "Not Applicable" and when you run the procedure, only the "Options" "Clear Screen after Running Procedure" and "Clear Field on Editing" are available. Move the cursor to somewhere near the middle of the screen and type:- "Which Aircraft type would you like listed". Then press F10 to define a field. If, in the aircraft form the "Type" field had been defined as a choice field, then we would define this field as a choice field and use the same list. If, on the other hand the "Type" field in the "Aircraft" form - 32 - ................................................................................ looked up its contents from a core data form containing the type names then we would set the attributes:- Name type Data type text Field Length 15 (Same as the "Type" field in "Aircraft") Mandatory Yes User Entry Yes Display Field (or text or Alt colours as you wish) Derived No The field will of course be derived:- Lookup(Aircraft,type) but as we have not yet entered the relationship, we will leave the derived attribute set to "No" to prevent an error message when we save the screen. Save the screen. When you do, you will be asked to select between "Repeat Screen after F2" and "Run Once and Exit". If you choose the first option then the procedure will repeat until you press the Escape Key. If you choose the second option, control will return to the procedures menu after the report has been run. Now save the procedure. Let's call it "Aircraft By Type". You may have noticed that all Form, Field and Procedure names so far have been single words. There is no restriction on using multiple words in names but single ones make code much easier to read. The only good reason to use more than one word is in a reporting procedure name. After the procedure has been run the status line in Browse mode will be "Procedure:- Aircraft By Type" which makes more sense to an end user than "Procedure:- ACbytyp". Now go to Relationships and enter the relationship "Aircraft" between "Aircraft by Type" and "Aircraft" linking the two fields "Type". Reload the "Aircraft by Type" procedure and edit the Input screen setting the derived attribute to "yes" and entering the derivation formula:- Lookup(aircraft,type) Save the screen again and select "Edit Procedure Code". To use the Input screen quickly you could change the two occurrences of "Bomber" to input.type. However, now that we have an input.type field the variable "group" is superfluous. The finished procedure code and Output format are shown on the next page. - 33 - ................................................................................ Declare output fields Aircraft.knownas : Aircraft.base Page number : input.type end Print report header for aircraft with typename > input.type if bottom margin < 1 then print report footer page feed : print page header end if if aircraft.type <> input.type then exit for print list items next print report footer page feed ......................Output Format......... .Report Header LIST Name Built at .Page header Name Built at .List items .Page Footer - .Report Footer .End The field in the Report header is input.type. The fields in the list items are Aircraft.knownas and Aircraft.base. The field in the page footer is Page number. Suppose now that we print out the report and find that we had entered all the "Aircraft" "Knownas" fields in Upper case and all the "Base" fields in Lower case. This would make the report quite untidy. There is no need however to change the original data. To print both fields in Upper case all we need to do is alter each of the "Base" field contents using the "Upper" Function before printing it. To do this insert the line:- - 34 - ................................................................................ aircraft.base = upper(aircraft.base) immediately before the print list items command. As well as simply "Listing" data you can manipulate it in many different ways. You can do any form of arithmetic on numeric fields and you can alter text, date and time fields with over fifty different functions. A function is a small internal routine which returns a value derived from one or more other values (Parameters) which you supply. For Example, in the code line:- date = datetext(invoice.date) "Datetext" is a function to which you are passing the parameter "Invoice.date". If invoice.date is 02/02/94 then the function "Datetext" will derive the text "2nd February 1994" and "Return" this as if it were a variable. The output field "Date" will therefore become "2nd February 1994". A functions parameters are always passed to it enclosed in brackets. If there are more than one then they are separated by commas. The next section of the Manual introduces you to Procedures which perform transactions. You should now read the descriptions of the following commands in the Programmers Reference. Copy All From Delete Record Clear Records From Update Record Pause On/Off Escape On/Off Together with the field control "Beep". Note: From Version 7 Procedures with input screens can be innitiated with any of the function keys 2,4,5,,7,8,9 or 10 See Programmers Ref. Procedure command "Run" - 35 - ................................................................................ PROCEDURES (TRANSACTIONAL) In Data Entry you make a "Transaction" when you add, update or delete a record. You can make the same transactions in procedures. There are, however, two major advantages to making your transactions via procedures. 1. You control which transactions can and cannot be made. 2. You can make any number of different transactions in any number of different forms. Consider the "Customers" form. You would want any of your staff to be able to add a new customer in your absence. If you allow them to do this in Record Entry then they could also (deliberately or inadvertently) alter or delete other customers records. To prevent this, create a new procedure. Create an input screen. When you are asked if you wish to copy an existing form - reply "Yes" and select the customers form. Save the input screen and select Create Procedure Code. Now enter the procedure code:- for customers new record copy all from input next Save the procedure - Let's call it "Enter customers". You can now call this procedure from your "User Menus" described in the next section and your staff will be able to enter new customers without the opportunity to make any other transactions. You can also control parts of a transaction. If your "Customers" form had a field for "Creditlimit" then, in the form, you would wish to be able to enter any credit limit you wanted, but you might wish to restrict the amount your staff could enter for a new customer. To do this you simply edit the field attributes for the "Creditlimit" field in the input screen. To set a fixed credit limit of say 500.00 set the user entry attribute to "No", the derived attribute to "Yes" and enter the derivation formula:- 500. To restrict the entry to a maximum of say 1000.00 you would leave the user entry attribute set to "yes" but derive the field:- If(creditlimit > 1000,blank[beepMaximum credit for new customers],creditlimit) There might also be fields on the "Customers" form which are - 36 - ................................................................................ irrelevant to the transaction of adding a new customer. You might also have fields for personal comments which you do not wish your staff to see. You can simply delete these from the input screen or change them to invisible. In other words you can limit a transaction in any way you wish and the final input screen can be totally different to the original form. Transaction procedures which delete or update records are created in a similar manner but are slightly more complicated. To create a procedure which allows your staff to delete customers, you would again copy the customers form as the input screen. This time, the only field to which you allow User Entry is the "acountno" field. You enter a relationship between this report and the "Customers" form linking "acountno" and derive all the other fields you wish to show as:- lookup(customers,name) lookup(customers,address) Etc. Your staff now enter the account number to be deleted. The other "looked up" fields are only there so that the name and address will appear confirming that the correct account number has been entered. The procedures code to delete the record is:- for customers with acountno = input.acountno delete record next As with the procedure to add a record you are still in complete control of what can or cannot be done. Suppose that you had a field on the "customers" form which you kept updated with his account balance. You would not want anyone to delete a customer who still had an outstanding balance on his account. To prevent this, just change the derivation for the "balance" field to :- if(lookup(customers,balance) <> 0,blank[beepCustomers cannot be deleted until their A/C is clear],0) You would also set the Mandatory attribute to "Yes" to prevent anyone from ignoring the warning. If you wanted a procedure which allowed staff to change a customers address but no other fields, then you would create the same input screen as for the delete record and the same - 37 - ................................................................................ relationship but this time you would allow user entry to the address field and derive it:- Default(lookup(customers,address)) When the operator enters the account number for the customer whose address he wishes to change, the old address will appear to confirm that he has the right customer, but he will be able to edit it. The procedure code would be:- for customers with acountno = input.accountno customers.address = input.address update record next The second advantage of making transactions via procedures is that you can perform several tasks at once. Consider a Video Library hiring films to its members. There will be a form for the films, one for the members and one for daily takings. The procedure used for hiring out the films will have an input screen with a field for the members number, possibly three fields for the film numbers being hired, three more fields in which the films rental prices are looked up and one in which these three fields are totalled. When the operator runs the procedure all the necessary transactions are performed by the procedure code:- for members with number = input.member if input.film1 <> blank then members.film1 = input.film1 if input.film2 <> blank then members.film2 = input.film2 if input.film3 <> blank then members.film3 = input.film3 update record next if input.film1 <> blank then for films with number = input.film1 films.hiredto = input.member films.datehired = system date update record next end if for daily takings total = total + input.total update record next The mid section of the code updating film1's record would of course be repeated for film2 and film3 but has been omitted for clarity. - 38 - ................................................................................ USER MENUS Once you have created forms and procedures you can create an end user menu system to run them. You could wait till all your procedures are finished but you will get a much better feel for how your program is developing if you start and use a menu system as you go. Easy Base includes a User Menu call to its system menus so you can work from your own developing menu system while you are still developing your program. Select "Menus" from the main menu and have a look at the screen. The Menus screen is an internal form just like the ones you have created. You have all the same facilities to enter, update and delete menus that you have in Data Entry to one of your own forms. Let's create a menu based on some of the forms and procedures previously discussed. The first field on the menus form is "Menu Name". This is the unique field and a name must be supplied. We'll call it "Customers". The next field is "Menu Type". This is a choice field with two options, "Normal" and "Batch Execute". The "Batch Execute" option will be discussed later. For now, select "Normal". The third field is "Menu Title". Whatever you enter here will be displayed as a title (or heading) above your menu. The fourth field which is untitled on the screen is a choice field with the options, "Run on Number Key" and "Run on Return Key". If you choose the first option then the items on your menu will be run as soon as the item number is pressed and if you choose the second option then typing the item number will move the highlight bar to the selection but the item will not be called until the return key is pressed. In either case you will still be able to select items with the cursor control keys The next field asks for a "Sign on password" if a startup menu. You can start your application (program) on any menu that has a sign on password by restarting Easy Base and using that password instead of your developers password. In this case we are going to menu the reports which add, delete and alter a customers address. This will be a sub menu so we leave this field blank. The main section of the "Menus" form has three columns of nine fields. The first column is for the text to be displayed on the menu. The second is for the type of action (function) which is to be called. The third is for the individual item. - 39 - ................................................................................ With the cursor in the first text field we type:- Enter a New Customer and press return. As soon as the cursor moves to the first "Function" field a menu appears listing all the different functions that can be called. The first four choices allow you to:- 1. Run one of your procedures. 2. Recall the last output from one of your procedures. 3. Call the data entry screen for one of your forms. 4. Call another of your menus. The other functions are selected utilities from the system utilities menu which you may wish to provide to the end user without allowing him access to the entire system. Select "Run Procedure" and press return. When the cursor moves to the "Item" column Easy Base will list all your procedures. Choose "Enter customers". on the next two lines enter:- Delete Existing Customer Run Procedure Delete Customers Change Customers Address Run Procedure Address Change and press F2 to save the menu. Now let's make a start to the main "Startup" menu. We may not have any procedures to put on it yet but we can get started with an item to call data entry to "Customers" and one to call the "Customers" sub menu. Fill in a new menus record using the name "Main Menu", Type "Normal" and Title "- M A I N M E N U -". This time enter a startup password, say "Fred". Complete the Items section with:- Customers Records Data Entry Customers Customer Updates User Menu Customers Program Development System menus Press F2 to save this menu then press escape all the way out to the DOS prompt (or your hard disk menu system). Restart Easy Base. This time, when the sign on screen appears, enter "Fred" and press return. Instead of the system menus, you will see your "Main Menu". If you select item 1 the "Customers" form will come up. If you select item 2 your sub menu will be overlaid and you can run any of the three procedures on it. If you select item 3 you - 40 - ................................................................................ will be transferred to the Easy Base System menus where you can continue with the development of your program. Whenever you create new procedures or forms you can add them to your menu system. Suppose you would like the utilities, Backup Data, Restore Data and Install Printer to be available from your menu system. Create a new menu, let's call it "Utilities" with the items:- Backup data to disk Backup Data Restore data from disk Restore Data Install Printer Install Printer Save this new menu then edit your main menu to include the new item:- Utilities User menu Utilities When you have called the Easy Base system menus from one of your own menus then pressing escape does not exit the program, it returns you to your own menu. You close down by pressing escape from your main menu. When you get back to your "Main Menu" you will notice that the new "Utilities" item is not there. New Menu items cannot be added while the program is running. To incorporate the "Utilities" item you must again exit the program and restart with the password "Fred". As your program develops you can create as many menus as you need. Your "Main Menu" can call up to nine sub menus. Each of those can call another nine sub sub menus Etc Etc. You can also have additional startup menus with different passwords. These can either run completely different menus or can restrict different parts of the menu system to different users. When you start up on one of your menus systems Easy Base creates a default "Tree" structure for it. From whichever menu is on screen the escape key backsteps down the tree until you reach your "Main Menu" and then exits the program. If one of the "forward" menu calls crosses branches, ie it calls a menu which is also called from a lower level then subsequent presses of the escape key backstep down the current branch and not back "cross tree". You can also make menu calls from low to high levels. (a sub- sub- sub menu can have an item which calls the main menu). In some circumstances you may prefer a hierarchical rather than a tree structure where the main menu is recalled after each individual procedure. To accomplish this, each final item is placed on its own menu followed by a call to the main menu and - 41 - ................................................................................ the menu type is changed to "Batch Execute". When you create a "Batch Execute" menu then instead of displaying a menu for you to choose from, Easy Base executes each item on the menu in sequence and then returns to the menu which called it. With batch execute menus you can automate many of the processes in your application. If you have several printouts to be done each day you can have them all done from batch execute menus. Similarly, if you need to update many reporting procedures for later "Recall" to the screen, these can all be done at once. There is no limit to the number of procedures which can be batched - One batch menu can call another. If you create a "Startup" batch menu then, provided it does not call a "Normal" menu, Easy Base will perform all the tasks on the menu and then exit to DOS. If you create a "Startup" batch menu which eventually calls a "Normal" menu then the batch process stops at that point and the "Normal" menu becomes the main (root) menu. Pressing escape from this menu exits to DOS. it never returns to the startup batch menu which called it Start up batch menus are useful for running regular daily procedures and for forcing the user to check the system date and time. There are many other uses for batch execute menus. You can automate menu changes. If, for example, running one particular procedure is invariably followed by running one from a choice of three others then the menu containing the others can be batched after the first procedure. In Easy Base you can create quite long and complex procedures but they are eventually limited by memory constraints. If you ever run out of memory creating a long procedure then just split it and batch the parts. Don't forget to set the output of non print reports to "Disk" otherwise Browse Mode will be invoked. - 42 - ................................................................................ EXTERNAL FILE ACCESS In order to provide flexible import and export to data files external to your applications, Easy Base includes a complete set of low level file access commands. :- Open, Close, Seek Read, Write, Find, Shell and Erase. Full details of the commands and how to use them are given in the programmers reference but please read the following notes. You can only open one external file at a time but you can transfer data either way between it and any number of Easy Base files. You can open any number of external files within one procedure but you must close each before you open the next. In Easy Base all data is converted to a common type for processing. Within the system this has the advantage that you never need to worry about what type of data you are handling. You can assign a text field's value to a numeric field and you can assign the result of a calculation to a text field. However, in order to do this Easy Base pre processes text variables. If you are accustomed to file access, string manipulation and trimming functions then you may get unexpected results. Here are the rules: If you read a string to an Easy Base text field all leading and trailing spaces are removed. If the remaining string is longer than the declared field length then it is truncated to the field length. If you read a string to an Easy Base text variable then all trailing spaces are removed. Text Variables are variable length. If you wish to create a string with leading spaces for a write command then you must do it in a text variable. Text fields do not accept leading spaces. You can pad strings with spaces using the Spacepad and Jointext(stringof()) functions. If you read an ASCII line then it is read without the Cr/Lf sequence. You can read ASCII directly into numeric fields. The data in an Easy Base Text Block field is formatted with a single Chr$(13) wherever a new line is to be forced. To read ASCII to a Text Block field, read lines to a variable - 43 - ................................................................................ then join the variable to the field with an intervening CHr$(13). Ex. read line to LineVar Pupils.notes = Jointext(pupils.notes,Chr$(13),Linevar) To Write a Text Block field as ASCII lines use the keyword Line_Len in the write command. Ex. write Pupils.Notes Line_len 60 You cannot write quotation marks within quoted text. Whenever Easy Base processes a text field, variable or read in string it substitutes Chr$(127) for internal quotation marks and replaces them after the process. This substitution is not done for direct assignments. TextVar = "Fred said "Hello"" is not allowed. If you need to make such an assignment then you must replace the internal quotation marks with Chr$(127) yourself. To create CHR$(127) in the procedure editor, hold down the ALT key and type 127 on the numeric keypad. - 44 - ................................................................................ EASY BASE DATA FILE FORMAT Easy Base data files are fixed length record files with no field separator. There is no file header. There is a three byte record header. Byte one is "L" for a live record and "D" for a record marked for deletion. Bytes 2 and 3 are null. The field order is top left to bottom right from the default input screen. All text fields are ASCII. All numeric, date and time fields are Microsoft 8 Byte double precision numbers. In the case of dates, this represents the number of days from the first of January 1981 and in the case of time, the number of seconds from midnight. - 45 - ................................................................................ SYSTEM REQUIREMENTS Required. IBM or compatible 286 or higher 1Meg Ram 540k free conventional memory (570k in Network Version) Preferred. 4 Meg expanded memory with 2 Meg allocated to PC-Cache NOTE:- If you have 2 Meg of expanded memory then certain EMS managers can cause Easy Base not to load with the error message "Insufficient EMS to load overlays". If this happens to you then you can load Easy Base in conventional memory by remming out the EMS driver in your Config.Sys file. SYSTEM LIMITATIONS Fields per Form 500 Indexes per Form 500 Record Length Limited by display of 4 screen pages Records per Form Limited by Maximum data or index file length of 2,100 Megabytes Forms per application } Total of 500 in Procedures per application } any combination. Menus per application 500 - 46 - ................................................................................ DOS FILENAME CONVENTIONS The Easy Base system files are:- EB.EXE The program file (EB.OVL Network) EB.CUR Initial screen setup EB.SET Configuration file (EB.C0, EB.C1 Etc. Network) EB.MEN User Menus form EB.REL Relationships form EB.MSG Text and error messages EB.PRS Printer drivers EB.D01 Main dictionary EB.DO2 Personal dictionary The files which are created in the data directories have the following filename convention:- Forms:- BASE(No).DEF The entry screen definition. BASE(No).DAT The data file. BASE(No).(No) Index files. Choice field lists LIST(No).DAT Procedures PROC(No).PRO The procedure code. PROC(No).DEF The input screen. PROC(No).REP Procedure output (Pre Network Versions) PROC(No).R(No) Procedure output (Network versions) There are also six individual files:- MENUS.DAT The menus you create. RELATION.DAT The relationships you create. CHOICES.DIR The choice list directory. BASE.DIR The forms directory. PROC.DIR The procedures directory. RECOVER.INF Recovery information to reinstate a form should you suffer a power failure during a pack or reformat operation. From V9 each form and procedure input screen also has a pre processed file: BASE(NO).PPR - PROC(NO).PPR. From Network V1 Private data and index files take the main file name overstamped from the second character by the terminal number. The file name for Terminal 12's private data for BASE6.DAT is B12E6.DAT - 47 - ................................................................................ Easy Base is a registered trade mark of John Turnbull. Easy Base documentation is copyright John Turnbull 1994. It may be freely distributed as part of the Shareware program and users of Easy Base may print a single copy of the documentation for their own use. All other rights are reserved. Trade marks of any other company included in the documentation are acknowledged. John Turnbull disclaims all warranties as to this software, whether express or implied, including without limitation any implied warranties of merchantability, fitness for a particular purpose, functionality, data integrity or protection. - 48 - ................................................................................ SELECTED PROGRAMMING TOPICS Address Labels 50 Automatic Lookups 52 Batch Starting 53 Check Off Fields 54 Compound Index 55 Compound Lookups 58 Conditional Lookups 59 Correcting Stats. 60 Creating Runtime 61 Customize Help Line 62 Cyclic Procedures 63 Data Type Conversion 64 Duplicate Prevention 65 Form Letters 66 Global Defaults 68 Input Screen Format 69 Invoicing/Ordering 70 Keyword/Text Search 73 Linking Applications 75 Maximizing Speed 76 Multiple Columns 78 Printing System Val. 79 Q And A Input Screen 80 Runtime Auto Start 81 Set System Values 82 Tabulation 83 Totals & Sub Totals 84 - 49 - ................................................................................ ADDRESS LABELS ADDRESS LABELS The following procedure prints two columns of address labels from a "Addr" form. .......................Procedure code................ Declare output fields Addr.name : Addr.street : Addr.town : Addr.pcode Lname : Lstreet : Ltown : Lpcode end for Addr if Lname = blank then Lname = Addr.name : Lstreet = Addrstreet Ltown = Addr.town : Lpcode = Addrpcode else print list items Lname = blank : Lstreet = blank Ltown = Blank : Lpcode = blank end if next if Lname <> blank then print list items ....................Output Format........................ .List Items {Lname field } {Addr.name field } {Lstreet field } {Addr.street field } {Ltown field } {Addr.town field } {Lpcode field } {Addr.pcode field } .end The field positioning and the distance between the .List Items and .end can be adjusted to fit the label paper. If your label paper has three columns then you could use the following procedure. declare output fields Addr.name : Addr.street : Addr.town : Addr.pcode Mname : Mstreet : Mtown : Mpcode Lname : Lstreet : Ltown : Lpcode end declare variables x as number end Continued. - 50 - ................................................................................ ADDRESS LABELS ADDRESS LABELS for addr x = x + 1 if Mod(x,3) = 1 then Lname = Addr.name : Lstreet = Addr.street Ltown = Addr.town : Lpcode = Addr.pcode end if if Mod(x,3) = 2 then Mname = Addr.name : Mstreet = Addr.street Mtown = Addr.town : Mpcode = Addr.pcode end if if Mod(x,3) = 0 then Print list items Lname = Blank : Lstreet = blank Ltown = blank : Lpcode = Blank Mname = Blank : Mstreet = blank Mtown = blank : Mpcode = Blank end if next If Lname <> blank then print list items .........................output format................... .list items { Lname } { Mname } { Addr.name } { Lstreet } { Mstreet } { Addr.street } { Ltown } { Mtown } { Addr.town } { Lpcode } { Mpcode } { Addr.pcode } .end See Also:- Form Letters - 51 - ................................................................................ Automatic Lookups Automatic Lookups Normally, when a user initiates a primary lookup in a text field he will enter a few characters followed by the * in order to narrow down his choice list. If, however, the possible list is fairly small you may wish to have it displayed automatically as if it was the list for a choice field. For example, you have a departments form with a field "name" and there are only twelve records. When entering records to your "Employees" form which has a field for his department, you wish to lookup the department name. If you derive the Department field on this form as "Lookup (Departments,name) and allow user access to it then the user must type at least an * and press return to bring up the list of department names. You can make this list pop up automatically by setting user entry to the department field to "no" and deriving it with the formula: If(Department = Blank,"*",Lookup(Departments,Name)) In other words the derivation formula automates the typing of the *. Please note that all forms and input screens must have at least one field to which the user has access. If you wish to make an automatic lookup on a procedure input screen that only has one field then you must add a second field purely to hold the cursor. This can of course be invisible. - 52 - ................................................................................ BATCH STARTING BATCH STARTING You can by pass any or all of the sign on parameters either by setting them in the environment or by supplying them on the command line. To log on as terminal one in the sub directory accounts using the password "Fred", add the following lines to your autoexec.bat file:- SET EBT=1 SET EBD=ACCOUNTS SET EBP=FRED Or start Easy Base with the command line :- EB T=1 D=ACCOUNTS P=FRED The terminal number parameter applies to network versions only. Any parameters which are not supplied either in the environment or on the command line will be asked for on start up. If you have set the start up parameters in the environment and you start Easy Base with different parameters on the command line, The parameters on the command line override those in the environment. If your application has different passwords for different menu structures you can set the terminal number and directory and leave the user to supply the password. If the user has access to different directories then just set the terminal number and the user can choose the directory and enter the password. See also Runtime Autostart - 53 - ................................................................................ Check off fields Check off fields Occasionally you may wish to have a field which is simply used to mark or "Check off" items to be done or printed. There is no graphical output from Easy Base but you can create a reasonable check off field by making it a choice field and using the two choices ASCII 255 and ASCII 251. You must use ASCII 255 as the blank as a "Blank" choice is deleted at run time and ASCII 251 ( ) which is actually the square root sign makes a reasonable "Tick". To enter the characters, hold down the Alt key and type the number on the numeric key pad. To have a form or input screen display with the items ready ticked, just define the tick fields with this choice list, derive them as Default( ) and make the color Text, Alt1 or Alt2. Easy Base will automatically display the help line "Press the space bar to change". - 54 - ................................................................................ COMPOUND INDEX COMPOUND INDEX If you need to list records from a form in such a way that they are grouped by one field but with each record in the group ordered by another then you can either use a compound index field or "Subindex" the group during the procedure. A compound index field is simply an additional field in which the contents of two or more fields are compounded using the "Jointext" function. The field is indexed and the index on that field can then be used to select records with the desired group ordering. For example:- A "Videos" form has fields for "Title", "RentalPrice" and "Category". To list the records grouped by "Category" but with the "Titles" in each category in alphabetic order you add another field to the form which is Text, Indexed and long enough to hold the contents of both the "category" and "Title" fields. The field is derived by joining the text of the "Category" and "Title" fields. There are a couple of minor complications in creating compound index fields. Firstly the "Jointext" function by default strips any trailing space characters from the text it is joining. If a straight "Jointext" function was used and the first two videos entered were "A Bridge Too Far" and "Snow White" then the compound fields would derive as:- "WarA Bridge Too Far" and "CartoonSnow White" When what you need is:- "War A Bridge Too Far" and "Cartoon Snow White " To produce the desired spacing in the compound field use the "Spacepad" function. If the length of the "Category" field is 15 then derive the compound field with - Jointext(spacepad(category,15),title) If you are compounding more than two fields then "spacepad" all the fields being joined to their own field's length except the last one. The maximum length of a text field in Easy Base is 80 characters. If the fields you need to compound total more than 80 then you must reduce the length of the field names. Compound indices in Text Block fields should not be used. - 55 - ................................................................................ COMPOUND INDEX COMPOUND INDEX Once you have created a compound field and checked that it derives correctly it is normal to define it as invisible and no entry anyway as it is not its contents that are of interest but the order which its index produces. Ex. Assuming the compound field was called "catgroup" ..........................code.................. for videos with catgroup in order print list items next ........................format................. .List Items {Videos.Category Field} {Videos.Title Field} .End Ex. ...........................code.................... declare variables catcheck as text end for videos with catgroup in order if catcheck <> videos,category then print group header catcheck = videos.category print list items next ..........................format............... .Group Header ------------------------------------- Films categorized as {category field} ------------------------------------- .List Items {Title field} .End There is yet a further complication if one or more of the fields to be compounded is numeric. Easy Base index files are sorted alphabetically if the field is text and numerically if the field is numeric. A compound field is always text so if you need to compound a numeric field you have to ensure that it will sort alphabetically to the same order that it sorts numerically. The text of numeric values sort alphabetically to the same order as their values only if they all have the same number of digits either side of the decimal point. 6 12 and 34 sort alphabetically as 12 34 6 but 06 12 and 34 sort alphabetically as 06 12 34 - 56 - ................................................................................ COMPOUND INDEX COMPOUND INDEX Easy Base provides the function "Zeropad" to pad numbers to the same length for compounding. The "Zeropad" function has three parameters - The number to be padded, the number of digits left of the decimal to pad to and the number of digits right of the decimal to pad to. All three parameters must be supplied. If the number is an integer then the third parameter is 0. Ex. To list the "Videos" records grouped by rental price with the titles in each price group in order you would create a compound field derived with:- Jointext(zeropad(rentalprice,2,2),title) Ex. A "Ships" form has fields for "Type" and "Displacement" To list the ships grouped by type with the Displacement in each group in order you would create a compound field derived with:- jointext(spacepad(type,15),zeropad(displacement,8,0)) In many cases where you wish to compound a mixture of text and numeric fields you will require the numeric values to be listed in descending order while the text value is to be in alphabetic order. In the above example for ships, had you wished each group to be listed with "Displacement" in descending order you would derive the compound field as:- jointext(spacepad(type,15),reverse(zeropad(displacement,8,0))) The "Reverse" function simply inverts the ACSII number of each character in its parameter so that it will sort in reverse order in the index file. The "Reverse" function works equally well on text values although reverse alphabetic lists are seldom required. The "Zeropad" function will only pad out a number to the size required. It will not trim the number if it is already longer than one of the pad lengths. You should not therefore create compound fields with Floating Point numbers. If you compound a date or time field you should zeropad it to 5,0 as the text which will be used is actually the date or time fields numeric value. - 57 - ................................................................................ COMPOUND LOOKUPS COMPOUND LOOKUPS Occasionally, in an input screen, you will wish to lookup details from a form whose unique field is a compound of two others. As an example, if you wished to lookup details from the "Userlist" form, mentioned in the manual, then you would have to base the lookups on a relationship between a field on the input screen and the "UNI" field in "Userlist". The "UNI" field in userlist is a combination of the "Aircraft" forms "Knownas" field and the "Airlines" form "Name" field. Although you could simply use a field "UNI" on the input screen and derive it :- Lookup(userlist,uni) - this would mean that the end user would have to enter the whole of the aircraft Knownas part plus part of the airlines name part plus the "*" in order to get the lookup. This would not only be awkward to use but would also entail explaining compound fields to the end user. You can avoid this situation by providing two fields, one in which the user looks up the aircraft knownas field and one in which he looks up the airline name. These are based on separate relationships between the input screen and the "Aircraft" and "Airlines" forms. The input screen's "UNI" field can now be made invisible with no user entry and derived:- Jointext(knownas,name). A relationship is entered between the input screen and the "Userlist" form linking the "UNI" fields and all the required details can then be derived :- lookup(userlist,whatever). - 58 - ................................................................................ Conditional Lookups Conditional Lookups Occasionally you may wish to use a single field either to initiate a lookup or to accept direct input from the keyboard. For example on an input screen to a procedure that enters invoice lineitems there is a field Partname which is related to the Name field in the "Parts" form. The entry to this field initiates a primary lookup for its own value and a secondary for the Price field. The user enters the first few characters of the part name followed by an *, then chooses the part name from the lookup list. If you also wish the user to be able to enter a partname that is not in the parts form then derive the partname field:- If(Intext(Partname,"*") > 0,Lookup(Parts,Name),Partname) If the user enters an * anywhere in the field then a lookup will be done from the parts form, but if he does not enter an * then the field will retain whatever name he entered. If you wish to be able to tell whether or not a lookup has been made for use in the procedure code - perhaps to add the new part to the parts form - then use a special character other than the * as the condition. For example, if you derive Partname as:- If(Lefttext(Partname,1) = "+",Partname,Lookup(Parts,Name)) then any entry to the field which starts with the "+" character will not initiate the lookup. You can then use the fact that the partname starts with a + to enter a new record in the parts form. Declare variables NN as text end NN = Input.partname If Lefttext(NN,1) = "+" then NN = righttext(NN,Lengthtext(NN)-1) For parts new record Parts.name = NN Next End if for Invoicelines copy all from input Partname = NN next - 59 - ................................................................................ CORRECTING STATS. CORRECTING STATS. If you write an application in which records are entered via procedures and "running" statistics are kept, you will have to provide procedures which allow the user to correct any mistakes he has made. For Example: - In a "Time Sheets" application the user enters a time and customer on the input screen of a procedure. The procedure then calculates the charge, writes the charge and customers name to the "Timesheet" form, adds the charge to the "Balance" field in the "Customers" form and also adds it to the "Total" field in the "Workinhand" form. If the operator makes an error then correcting the entry in the "Timesheet" form is simply a case of updating it but to correct the "Balance" and "Total" fields you must add the corrected value and subtract the old incorrect value. To get the two values together for your procedure, create an input screen where the operator enters the "line" ("line" is the unique sequenced field in "Timesheet"). Then create two fields for the values. The first, "oldval" is derived lookup(timesheet,charge) and the second, "newval" is derived default(lookup(timesheet,charge). The "Oldval" field can be invisible and has no user entry. You would also add two similarly derived fields "Oldcustomer" and "Newcustomer". When the user edits the "Newval" and/or "Newcustomer" field and presses F2 , all the required values are available to the procedure code:- pause off : escape off for timesheet with line = input.line timesheet.charge = input.newval timesheet.customer = input.newcustomer update record next for customers with name = input.oldcustomer customers.balance = customers.balance - input.oldval update record next for customers with name = input.newcustomer customers.balance = customers.balance + input.newval update record next for workinhand workinhand.total = workinhand.total+input.newval-input.oldval update record next - 60 - ................................................................................ CREATING RUNTIME CREATING RUNTIME To create a distributable application with the Easy Base Royalty free Runtime Module, first, ensure that your application has a user menu with a start up password. If you wish your runtime application to start without a sign on screen then this password should be "Autostart". Make a new directory for your module and copy all the files from the Easy Base sub directory in which you developed the application to it. Copy the Configuration file "EB.SET" from your Easy Base directory to this directory. Insert the Runtime Module disk in a floppy drive. Change to that drive and type "MODULE". The "Module" program will first ask you for the path to the application files. Once you enter this it will unpack the runtime files into your new directory. It will then ask for the name of your application. The name you supply here will be displayed on any sign on screens and also on the shutdown "Thank you for using - " line. It will then ask you for your copyright line. The text you enter here will replace the line "Application of Easy Base - Not for Resale" which appears above your menus. Finally, you will be asked for the Executable file name you wish to use for your program. When you have entered the details - Press F2 and your application will be complete and ready to sell. -------------------------- EASY INSTALL UTILITY For professional distribution disks just like the ones Easy Software is distributed on, you can purchase Easy Install. This utility will compress your application and create a distribution disk with an install program customized for your application. - 61 - ................................................................................ CUSTOMIZE HELP LINE CUSTOMIZE HELP LINE You can replace the default help line (bottom line) in both data entry and procedure input screens. Press F6 in form or input screen design to access the help line. If you wish to revert to the default help line just erase your customized one. The line which you enter here becomes the default but is overridden when the cursor is in any field with a Help prefix. - 62 - ................................................................................ CYCLIC PROCEDURES CYCLIC PROCEDURES In many applications you will come across the situation where you need a procedure which will perform the same actions on a given set of records. For example, in a payroll system the procedure which calculates the employees wage and deductions has to be repeated for each employee so that their hours can be entered. If you simply enter each employees Worksno and lookup his or her details then it will be easy to miss an employee or to do one twice. To avoid this you can create a procedure which will cycle each employee through the input screen and terminate when all employees have been processed. On the employees form, add a field "Cycled" which is a single character indexed field derived :- Default("N"). On the procedure input screen add an invisible field "Cycled" which is derived "N" You now enter two relationships between the procedure and the employees form. The main relationship "Employees" links the fields "Worksno" and the second, lets call it "Cycled" links the "Cycled" fields. On the input screen you derive the "Worksno" field as Lookup(cycled,worksno) and all the other details as lookup(employees,Whatever). When you run the procedure, the first employees details will be loaded automatically and all you have to enter are his hours. To have the next employee loaded after you run the procedure, the procedure code simply includes the lines:- for employees with worksno = input.worksno employees.cycled = "Y" update record next When all employees have been processed the "Worksno" field will derive blank as there are no employees with "N" in the "Cycled" field. You can therefore pass a "finished" message by altering the derivation of "Worksno" to :- if(lookup(cycled,worksno)=blank,blank[beepAll Employees have now been processed],lookup(cycled,worksno)) To reset cycling for the next payroll you write an additional procedure with the code:- for employees employees.cycled = "N" : update record next - 63 - ................................................................................ Data Type Conversion Data Type Conversion In Easy Base, modifying the structure of a data file after it contains data is very easy and flexible. If you select Modify Existing Form from the Forms menu you can add fields, delete fields, change field order, change field lengths and Easy Base will reformat your existing data automatically. You can NOT however change data types simply by changing the field type. If you change a field type and save the form you will almost certainly lose the data that was in that field. (Other than changing from one numeric type to another) If you work entirely within Easy Base there is no reason why you should ever need to change a field type. However, if you have imported data from Dbase or Fixed Length ASCII you may find yourself with numeric or date values held in text fields. The procedure for converting data from one type to another is as follows:- 1. Select Modify Existing Form 2. Add a new field of the desired type with a derivation formula such that it will derive its value from the field of the old type. 3. Save the form. 4. Select Modify the form again. 5. Cancel the derivation formula in the new field and delete the old field. 6. Re save the form. To derive a numeric field from a text field the derivation formula is simply the text field name. To derive a date field from a Dbase imported date in a text field called DT the formula is:- Makedate(midtext(DT,5,2),midtext(DT,7,2),midtext(DT,3,2)) Version 3.10 From V3.1 you can change field types between text and numeric and retain any numeric values that were in the field automatically . You still cannot change a field type from date or time to text or vice versa without following the above procedure. - 64 - ................................................................................ DUPLICATE PREVENTION DUPLICATE PREVENTION 1. Where "Blank" values are acceptable. Quite often you will come across a situation where a field must not have duplicate entries but can still be left blank. You cannot define this field as unique because that would prevent more than one blank entry. A good example of such a situation is in the "Menus Form" of Easy Base. The definition and unique field is the "Menu Title" but no two records may have the same entry in the sign on "Password" field. To prevent duplicate entries other than blanks you must enter a relationship between the form and itself with the field to be tested as the related field in both primary and secondary forms. The field is then derived as :- If(lookup(menus,password) <> blank,blank[beepDuplicate Password !],password) 2. When entering records via procedures. When you use a procedure to enter a new record to a form it is not automatically checked as "Unique". To ensure that duplicate entries are not entered via procedures you must check that the data entered on the procedures input screen is unique to the form you are about to enter it to before running the procedure. For example: If you were about to enter a record to the "Manufacturers" form in which the "Name" field was unique then the "Name" field on the input screen would be derived:- if(lookup(manufacturers,name) <> blank,blank[beepDuplicate Name !cursor name],name) - 65 - ................................................................................ FORM LETTERS FORM LETTERS To print form letters (circulars) with a different address and salutation for each entry in an address form simply type the entire letter between the .List Items and .End of the output format. .........................procedure code........ Declare output fields Addr.name : Addr.street : Addr.town Addr.salutation date end date = datetext(system date) for addr print list items page feed next .........................output format........ .List Items My street My county {date field } {Addr.name field } {Addr.street field } {Addr.town field } Dear {Addr.salutation}, You are invited................................ ................................................... ................................................... .......................................... Yours faithfully, Fred A Blogs .End Although this is the fastest way to produce a short form letter, the Format Editor is not the nicest place to write text. If you want the benefits of word wrap and spell checking then you can create a form in which to write the letter. Create text block fields to hold a page of text and a name field so that you can store many different letters and print them with the same procedure. If your letters are to be more than one page long then put the same name on each page. - 66 - ................................................................................ FORM LETTERS FORM LETTERS To print the form letters from the "Letters" form your procedure must now have an input screen which looks up the name of the letter to be printed. '............................CODE..................... declare output fields addr.name : addr.street : addr.town :addr.salutation date :letters.block1 :letters.block2 :letters.block3 end declare variables page as number end date = datetext(system date) for addr page = 0 for letters with name = input.name page = page + 1 if page = 1 then print list items if page > 1 then print extra page feed next next The output format is similar to that shown on the previous page but the text in the .list items section is replaced by the text block fields Letters.block1 ,letters.block2 and letters.block3 and an additional section .extra is added which has the same text block fields but no address or salutation. - 67 - ................................................................................ GLOBAL DEFAULTS GLOBAL DEFAULTS In many instances, an application will use the same default values in many procedures and field derivations. If you "hardwire" these as constants into your procedures and code then they will all have to be changed when the default value changes. Easy Base is supplied with a single global defaults form for VAT rates but you can create your own for any particular application. For instance, should you write a payroll system you would wish to be able to update the tax rates and bands globally throughout your application when they change. To do this, create a form to hold all the global defaults. In addition to the default fields add a single character text field derived "X" and index it. You then enter a single record with all the default values. The "X" field is there to create an artificial relationship between any input screen and the defaults form in order to lookup defaults. Wherever you need one or more global defaults in an input screen you simply add an invisible "x" field and enter a relationship between the procedure and the defaults form linking the "x" fields. The field "Tax" can now be derived:- taxablepay * lookup(defaults,taxrate) Similarly, you can pre load variables in procedure code for the default values:- Declare variables Taxrate1 as number:Taxrate2 as number Taxband1 as number:Taxband2 as number end for defaults Taxrate1 = defaults.taxrate1 :Taxrate2 = defaults.taxrate2 Taxband1 = defaults.taxband1 :Taxband2 = defaults.taxband2 next When the taxrates change you only have to alter them once in the Defaults form. - 68 - ................................................................................ Input Screen Format Input Screen Format All form and input screens can be presented either mounted in a window against a mottled background or exactly as drawn in form design. The windowing effect is done automatically if you leave a clear border around all text and fields. If you place fields or text anywhere against the edge of the screen (even invisible fields) then the window effect will not be invoked. If you do not want the window effect but you still wish to leave a clear border then you should place the invisible text character (ASCII 255) in the top left hand corner of the screen to disable it. To produce the invisible character hold down the Alt Key and type 255 on the numeric keypad. - 69 - ................................................................................ Invoicing/Ordering Invoicing/Ordering To create a simple order processing or invoicing system you need forms for : Stock (ID#,descrip,price,qtyonhand etc) Customers (ID#,name,address etc) Lineitems (Customer ID,Item ID,Qty,price) Last (Single record with Last invoice/order number) Current (Single record for current Cust ID/Invoice No) Both of the forms "Last" and "Current" also have a field called "X" which is a single character indexed text field containing the character "x" You also need three procedures: SelectCustomer EnterItems PrintInvoice The first procedure has an input screen on which you verify the Customers ID# for the invoice. Whether you do this by entering the ID# and looking up the name and address to verify it or by using a primary lookup on the customers name is up to you. The input screen also has an invisible single character text field which is derived "X" and an InvoiceNo field. As well as the relationship to lookup the customers name, the input screen is also related to the Last form linking the "X" fields. The InvoiceNo field is derived Lookup(Last,InvoiceNo) + 1 When you have looked up the Customer you run this procedure which has the code: ................................................... For Last Last.Invoiceno = Input.Invoiceno : Update Record Next For Current Current.Invoiceno = Input.Invoiceno Current.CustomerID = Input.CustomerID Update Record Next Run EnterItems .............................................. The second procedure "Enteritems" now takes over and it has an input screen where you lookup items from your stock form together with their price, and enter the quantity. This procedure has a repeating input screen. It is used to enter one line at a time into the LineItems form. You must also nominate a function key which will be used to run the PrintInvoice procedure when all invoice items have been entered. A suitable default help line might be:- - 70 - ................................................................................ Invoicing/Ordering Invoicing/Ordering "F2=Enter Invoice Item F4=Print Invoice F10=Cancel" It is important that the user should not terminate this procedure with the escape key so you should disable it and the other function keys in one of your field derivations: Disable "Esc5789" Like the SelectCustomer procedure this screen also has an invisible "x" field - no entry and derived "X". This time it is related to the X field in the Current form. There are fields for InvoiceNo and CustomerID. Both are no entry and are derived: Lookup(Current,InvoiceNo) Lookup(Current,CustomerID) The main relationship of course is to the Stock form to lookup the stock item and price. Again, like the first procedure, it is up to you whether you enter stock ID#s and lookup the description and price or do a primary lookup on the Stock Descrip field. This procedure writes a new record to the LineItems form if F2 is pressed, runs Printinvoice if F4 is pressed and "Tidies Up" if F10 is pressed. ................................................ If Fun_Key = 4 then run Printinvoice If Fun_Key = 10 then for LineItems with InvoiceNo = Input.InvoiceNo Delete Record Next For Last Last.Invoiceno = Last.Invoiceno - 1 : Update record Next Run SelectCustomer End if For LineItems new record Copy all from Input Next .............................................. The third procedure "PrintInvoice" is run when the user presses F4 and has the Following code. Declare output fields Customers.Name : Customers.Address LineItems.StockID : LineItems.Descrip : LineItems.Qty LineItems.Price LineTotal : SubTotal : Tax : GrandTotal InvoiceNo : CustomerID End '............Get Nos from Current For Current InvoiceNo = Current.Invoiceno CustomerID = Current.CustomerID Next - 71 - ................................................................................ Invoicing/Ordering Invoicing/Ordering '.......Print Customer details to invoice header For Customers with ID = CustomerID Print Report Header Next '.................Print Invoice Lines... For LineItems with InvoiceNo = InvoiceNo LineTotal = LineItems.Price * LineItems.Qty SubTotal = Subtotal + LineTotal Print List Items '........Update Stock on hand For stock with ID = LineItemsID Stock.Qtyonhand = Stock.Qtyonhand - LineItems.Qty Update Record Next Next ,..................Report Footer Tax = VATon(SubTotal) GrandTotal = Subtotal + Tax Print Report Footer Page Feed Notice that the Quantity on hand field in the stock form is not updated until you actually print the invoice. You could have done it while you were entering the Line Items but it would make the tidying process more complicated if the invoice were cancelled with F10 after items had been written. - 72 - ................................................................................ Keyword/Text Search Keyword/Text Search If you have a database with a large number of items where the user would be unlikely to know exactly what he is looking for you will need to provide a search facility based on text supplied by the user. There are two main ways to do this and both have advantages in different situations. Suppose you have a form for technical publications. There are fields for Name, Publisher, Price, Short Description Etc. A user wishing to search this form will not know the contents of any of the fields - he will only know the topic or subject which he wants to look up. You need to get some search text from the user, find the names of any publications which may cover the subject then make a short list of them in the PickList form. The simplest way is to have an input screen field where the user can enter search text, then search the "ShortDescrip" field for the occurrence of the text he has entered. Wherever his text is found you add a new record to the PickList form. The user can then mark the titles which interest him and you can print out the short descriptions of the publications he has chosen. Clear records from PickList for Publications If intext(shortdescrip,input.searchtext) > 0 then for PickList new record PickList.Item = Publications.Name next end if next Show Picklist For PickList with Mark = Chr$(251) For Publications with Name = Picklist.Item Print List Items next next The advantage of this method is that the user is free to enter any text and will get a "Hit" if it exists anywhere in the description. The disadvantage is that every record in the publications form has to be searched. This form of searching becomes too time consuming if there are many thousands of records. You can overcome the time problem in a large database by adding a KeyWord form. A KeyWord form has two fields, one for the publication name and one for a key word. Each publication can have several entries in this form with different key words. The Keyword field is indexed so if you now search this form for the entered text you will get a list of publications with the entered keyword very - 73 - ................................................................................ Keyword/Text Search Keyword/Text Search quickly. The disadvantage of this method is that the user will only get a "Hit" if he enters a word that you have chosen as a KeyWord. You can optimize this method by choosing Keywords that might contain text the user might enter within them. Eg use the keyword "Installation" rather than "Install" and make your routine select with >= rather than = Declare variables Len as number end Len = lengthtext(input.searchtext) For Keywords with Key >= input.searchtext if lefttext(keywords.Key,Len) <> input.searchtext then exit for end if for PickList new Record Picklist.Item = Keywords.Publication next Next Show Picklist For PickList with Mark = Chr$(251) For Publications with Name = PickList.Item Print List Items Next Next Entering Keyword records can be incorporated into the procedure which writes the Publications record to save time when entering data. For Publications new record Copy all from input Next for Keywords new record Keywords.Publication = Input.Name Keywords.Key = Input.Keyword1 next If Input.Keyword2 <> blank then For Keywords new record Keywords.Publication = Input.Name Keywords.Key = Input.Keyword2 Next End if Repeat last section for the number of keywords on the input screen. - 74 - ................................................................................ LINKING APPLICATIONS LINKING APPLICATIONS Procedures in one directory can access forms in another directory or disk by placing the external forms path in brackets immediately after the form name at the start of a For Loop. Ex. For payroll (c:\pay) with posted = "No" for purchaseledger new record copy all from payroll next payroll.posted = "Yes" update record next The above procedure, in an accounts application, imports data from a payroll application in C:\PAY and updates the "Posted" field in the payroll application. Ex. for sales (A:\) alias import for sales new record copy all from import next next The above procedure is used to import data transferred from one machine to another on floppy disk. Note:- 1. If transferring data on floppy disk the floppy must hold the forms .DAT and .DEF files together with the BASE.DIR from the source application. If you need to move large amounts of data on floppy it is much quicker to simply overwrite an import forms .DAT file and then pack it to rewrite the indices. - 75 - ................................................................................ MAXIMIZING SPEED MAXIMIZING SPEED Because the procedures you create in Easy Base have to be interpreted each time they are run they will tend to be slower than similar routines created in a compiled system. This is the unavoidable cost of ease of use. You can increase speed vastly by having the best DOS environment and by the way in which you write procedure code. DOS Environment. 1. Do not use a disk compression system. 2. Always load "Fastopen" - The default settings are fine - just add the line "fastopen C:" to your AUTOEXEC.BAT file. 3. Use a Disk Cacheing system - The more memory you can allocate to it the better. Easy Software recommends PC-Cache from Centre Point with 2 Megabytes of expanded memory allocated. Smartdrive (Version supplied with Windows 3.1) was slightly faster but caused widespread disk corruptions during test "Power Failures". 4. Do not run any TSR programs (Especially Virus Checkers). Procedure Code. Avoid making calculations and derivations within "For" loops in procedures. If, for example, you had a form in which was recorded the length, breadth and depth of various blocks and you knew that at some point you would write a procedure which listed their volume. Add a field for volume to the form and derive it from the other fields. When you write the procedure you will simply list this field. If the field had not been added to the form then you would have to calculate its value on each iteration of the "For" loop. The time taken to derive each individual "Volume" field during record entry will not be noticeable but the time taken to derive the volume for every record during the procedure will. Keep "Running statistics". If your program requires statistics derived from many hundreds or even thousands of records then having to wait for a procedure which calculates them each time you want up to date figures is a real pain. To keep "running statistics" create a form with a field for each statistic you require and enter a single record with zero values in each field. Make all entries, modifications and deletions to your data via procedures and you can update your statistics each time a record is added, modified or deleted. Example on next page. - 76 - ................................................................................ MAXIMIZING SPEED MAXIMIZING SPEED The following procedure code enters a record (collected via the input screen) to a purchases ledger and updates statistics used in the profit and loss account. It also updates the balance for the suppliers account. pause off : Escape off for purchases new record copy all from input next for stats if input.type = "Invoice" then stats.creditors = stats.creditors + input.amount end if if input.type = "CreditNote" then stats.creditors = stats.creditors - input.amount end if if input.type = "Payment" then stats.creditors = stats.creditors - input.amount if input.paidby = "cash" then stats.cashbalance = stats.cashbalance - input.amount else stats.bankbalance = stats.bankbalance - input.amount end if end if next for ACbalances with supplier = input supplier if input.type = "Invoice" then ACbalances.balance = ACbalances.balance + input.amount else ACbalances.balance = ACbalances.balance - input.amount end if next Whenever you need to know statistics for "Debtors", "Cash Balance" etc you can produce them instantly with a procedure which simply lists data from the statistics forms. Whenever you use running statistics in this way you should also create a procedure which does calculate them from the raw data. If you ever, for one reason or another, have to edit data directly in "Data entry" then your "running statistics" will no longer be accurate. You can run this procedure to correct them. - 77 - ................................................................................ MULTIPLE COLUMNS MULTIPLE COLUMNS You may occasionally need to list data in order but in more than one column. Indexes for technical manuals are a common example. It would be nice if you could send the printer head back to the top of the page for each column but you can't. You must therefore get all the data for each horizontal line into memory at the same time and then print it. The following example prints the "Title" field from a "Films" form in alphabetic order in two columns with fifty lines on each page. To do this a field "No" is added to the form. This is an integer field and it is indexed. declare output fields films.title : righttitle end declare variables x as number : y as number : lasttitle as text end '................UPDATE THE No FIELD...... for films with title in order y = total records x = x + 1 display status "Updating No field record" + x + "of" + y films.No = x update record next '.................PRINT IN TWO COLUMNS................. x = 0 'reuse x as counter do for films with title > lasttitle x = x + 1 for films alias col2 with No = films.No + 50 righttitle = col2.title next print list items lasttitle = righttitle : righttitle = blank if mod(x,50) = 0 then page feed : Exit for end if next if lasttitle = blank then exit do loop ........................Format.................. .list items { Films.title field } { Righttitle Field } .end - 78 - ................................................................................ Printing System Val. Printing System Val. In Easy Base procedures most system values are supplied as fields and can be declared as output fields. Others are internal values and cannot. The internal values are:- System Date System Time Pi Terminal Number To print an internal value you must declare an ad hoc field and transfer the system value to it. Declare output fields date end date = system date - 79 - ................................................................................ Q AND A INPUT SCREEN Q AND A INPUT SCREEN If, for a procedure you have to collect many items of data via an input screen, then presenting all the fields and their labels at once can be confusing to an operator. You can start with an empty screen other than the first field and its prompt then have each subsequent prompt "Pop up" when the previous field has been filled. To do this you make all your input fields without a background (Text, Alt1 or Alt2) and you create fields for the prompts which have no user entry and also show no background. Ex. To collect data for paymethod, customer, and amount lay out the following fields:- Enter Method of payment.... { Paymethod Field } { Pop1 Field } { Customer Field } { Pop2 Field } { Amount Field } The "Pop1" field is derived:- If(Pop1 = blank and paymethod = blank,blank,"Enter Customers name.........") and the "Pop2" field is derived:- If(Pop2 = blank and customer = blank,blank,"Enter Amount... ...............") - 80 - ................................................................................ RUNTIME AUTO START RUNTIME AUTO START If you intend to distribute an application using the Easy Base Runtime Module, you can have the module start automatically on a particular user menu by giving that menu the sign on password "Autostart". Each time the runtime module starts it searches for a menu with this password. If it finds one, it skips the sign on screen and starts automatically on this menu. The "Autostart" password has no significance while developing in Easy Base. It is treated as any other sign on password. - 81 - ................................................................................ SET SYSTEM VALUES SET SYSTEM VALUES The System values System date, System Time and Output can be set within procedure code. Ex. System Date = input.date Ex. If input.print = "Yes" then Output = "Printer" Setting the output from an input screen field means that the user can change the output destination without having to exit back to the menu in procedures which have repeating input screens. If you have several procedures which are individually run to the screen but you also wish to batch execute them to the printer, you can achieve this by including the line:- If Global number = 2 then output = "Printer" then placing the procedures on a batch execute menu which begins with a procedure setting Global Number to 2. and ends with one re setting it to zero. - 82 - ................................................................................ TABULATION TABULATION To create a printout in which fields are enclosed within a lined table use the linedrawing facility in the format editor to create a page header and page footer containing the top and bottom of the table and insert only the vertical lines between the fields in the list items section. Ex. Declare output fields stock.name : stock.price end print page header for stock with name in order if bottom margin < 0.7 then print page footer page feed print page header end if print list items next print page footer Page feed ........................format......................... .page header Name Price .list items {Name Field } {Price Fld. } .page footer .end - 83 - ................................................................................ TOTALS & SUB TOTALS TOTALS & SUB TOTALS To produce totals and sub totals in printouts use ad hoc fields to hold the values and increment them during each iteration of the output loops. The following code lists all entries in a clients time sheet form with the cost of work in hand totalled and sub totalled for each client. Declare output fields Clients.Name:Timesheet.Hrs:Timesheet.Mins:Timesheet.Amount Timesheet.date : Subtotal : Grandtotal end Print Report Header for Clients with name in order Print Group Header Subtotal = 0 For Timesheet with Acno = Clients.Acno Subtotal = Subtotal + timesheet.amount Grandtotal = Grandtotal + Timesheet.amount Print List Items next Print Group Footer next Print report footer .......................Output Format......................... .Report Header Work in Hand Totalled by Client .Group Header .List Items Mins .Group Footer Total for .Report Footer Total Work In Hand .end The field in the Group Header is Clients.name The fields in List Items are Timesheet.date, Timesheet.Hrs, Timesheet.Mins and Timesheet.amount. The fields in Group Footer are Clients.name and Subtotal. The field in Report Footer is Grandtotal. - 84 - ................................................................................